自 Spring 3.1 起,框架引入了基於註解的緩存抽象層,這並非一個具體的緩存實現(如 Ehcache、Caffeine),而是定義了一組標準化的 API 與註解(@Cacheable、@CachePut、@CacheEvict 等),讓開發者能以最小代價為既有業務方法賦予緩存能力。其核心優勢在於:業務邏輯與緩存邏輯解耦、支援 SpEL 表達式靈活定義 Key/條件、開箱即用的 ConcurrentMap 後端、以及與專業緩存中間件無縫整合。
早期開發者常在 Service 方法中手工操作 Map 結構作為緩存,導致:
以帳號查詢為例,僅需在方法上添加 @Cacheable(value="accountCache"),並配置 <cache:annotation-driven/> 與 SimpleCacheManager,即可實現首次查詢走 DB、後續命中緩存的效果。配置片段:
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="accountCache"/>
</set>
</property>
</bean>
| 註解 | 用途 | 關鍵屬性 |
|---|---|---|
| @Cacheable | 查詢緩存,命中則跳過方法執行 | value, key, condition, unless |
| @CachePut | 強制執行方法並將結果更新至緩存 | value, key |
| @CacheEvict | 清除緩存條目 | value, key, allEntries, beforeInvocation |
@Cacheable(value="accountCache", condition="#userName.length() <= 4") 僅緩存短用戶名@Cacheable(key="#userName.concat(#password)") 多參數構建唯一鍵@CacheEvict(key="#account.getName()") 精準失效更新操作建議使用 @CachePut 保證方法執行並刷新緩存;批量清除用 @CacheEvict(allEntries=true)。注意 beforeInvocation=true 可在方法執行前清除,避免異常導致緩存殘留。
Spring Cache 基於 Spring AOP 的動態代理機制:容器為目標 Bean 生成代理,攔截方法調用,在切面中實現緩存查找、存儲、失效邏輯。關鍵限制:僅對外部調用生效,同類內部調用(this.method())繞過代理導致緩存失效,解決方案包括注入自身 Bean 或改用 AspectJ 編譯時織入。
實現 CacheManager 與 Cache 接口即可對接 Redis、Memcached 等。示例中自定義 MyCache 覆寫 get/put 方法,並在配置中替換 cacheManager Bean,驗證緩存確實生效(通過修改返回對象屬性標記)。
beforeInvocation=trueCompositeCacheManager + fallbackToNoOpCache=true 實現優雅降級Spring 註解驅動緩存以「零侵入、高擴展、強表達力」顯著降低緩存接入成本。掌握 SpEL、AOP 代理邊界、自定義 CacheManager 擴展點,即可應對從單體到分布式的各類緩存場景。