1. pom文件導入jar包
<!--ehcache緩存框架-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.2</version>
</dependency>
2. Spring添加配置文件整合EhCache
2.1 新建EhCache配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!-- 磁盤緩存位置 -->
<diskStore path="java.io.tmpdir/ehcache"/>
<!-- 默認緩存 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!--獲取企業微信應用的accessToken-->
<cache name="accessTokenCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
/>
<!--獲取企業微信通訊錄接口憑證accessToken-->
<cache name="weChatAccessTokenCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
/>
<!--企業的jsapi_ticket緩存-->
<cache name="jsapiTicketCache"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>
2.2 新建spring-ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 支持緩存註解 -->
<cache:annotation-driven cache-manager="cacheManager" />
<!-- 默認是cacheManager -->
<bean id="cacheManager" name= "cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean>
<!-- cache管理器配置 -->
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache/ehcache.xml"/><!-- ehcache.xml的路徑 -->
</bean>
</beans>
org.springframework.cache.ehcache.EhCacheManagerFactoryBean這個類的作用是加載Ehcache配置文件。
org.springframework.cache.ehcache.EhCacheCacheManager這個類的作用是支持net.sf.ehcache.CacheManager
2.3 將spring-ehcache.xml引入spring-mvc.xml配置文件
<import resource="classpath:spring-ehcache.xml"/>
配置好就可以使用spring的緩存註解使用緩存了
3. 使用spring緩存註解
Spring對緩存的支持類似於對事務的支持。
首先使用註解標記方法,相當於定義了切點,然後使用Aop技術在這個方法的調用前、調用後獲取方法的入參和返回值,進而實現了緩存的邏輯。
3.1 @Cacheable
表明所修飾的方法是可以緩存的:當第一次調用這個方法時,它的結果會被緩存下來,在緩存的有效時間內,以後訪問這個方法都直接返回緩存結果,不再執行方法中的代碼段。
這個註解可以用condition屬性來設置條件,如果不滿足條件,就不使用緩存能力,直接執行方法。
可以使用key屬性來指定key的生成規則
@Cacheable支持如下參數:
- value:緩存位置名稱,不能爲空,如果使用EHCache,就是ehcache.xml中聲明的cache的name, 指明將值緩存到哪個Cache中
- key:緩存的key,默認爲空,既表示使用方法的參數類型及參數值作爲key,支持SpEL,如果要引用參數值使用井號加參數名,如:#userId,
一般來說,我們的更新操作只需要刷新緩存中某一個值,所以定義緩存的key值的方式就很重要,最好是能夠唯一,因爲這樣可以準確的清除掉特定的緩存,而不會影響到其它緩存值 ,
本例子中使用實體加冒號再加ID組合成鍵的名稱,如”user:1”、”order:223123”等 - condition:觸發條件,只有滿足條件的情況纔會加入緩存,默認爲空,既表示全部都加入緩存,支持SpEL
// 將緩存保存到名稱爲UserCache中,鍵爲"user:"字符串加上userId值,如 'user:1'
@Cacheable(value="UserCache", key="'user:' + #userId")
public User findById(String userId) {
return (User) new User("1", "mengdee");
}
// 將緩存保存進UserCache中,並當參數userId的長度小於12時才保存進緩存,默認使用參數值及類型作爲緩存的key
// 保存緩存需要指定key,value, value的數據類型,不指定key默認和參數名一樣如:"1"
@Cacheable(value="UserCache", condition="#userId.length() < 12")
public boolean isReserved(String userId) {
System.out.println("UserCache:"+userId);
return false;
}
3.2 @CachePut
與@Cacheable不同,@CachePut不僅會緩存方法的結果,還會執行方法的代碼段。它支持的屬性和用法都與@Cacheable一致。可以用來更新緩存。
3.3 @CacheEvict
與@Cacheable功能相反,@CacheEvict表明所修飾的方法是用來刪除失效或無用的緩存數據。
@CacheEvict 支持如下幾個參數:
- value:緩存位置名稱,不能爲空,同上
- key:緩存的key,默認爲空,同上
- condition:觸發條件,只有滿足條件的情況纔會清除緩存,默認爲空,支持SpEL
- allEntries:true表示清除value中的全部緩存,默認爲false
//清除掉UserCache中某個指定key的緩存
@CacheEvict(value="UserCache",key="'user:' + #userId")
public void removeUser(User user) {
System.out.println("UserCache"+user.getUserId());
}
//清除掉UserCache中全部的緩存
@CacheEvict(value="UserCache", allEntries=true)
public final void setReservedUsers(String[] reservedUsers) {
System.out.println("UserCache deleteall");
}
3.4 @Caching
如果需要使用同一個緩存註解(@Cacheable、@CacheEvict或@CachePut)多次修飾一個方法,就需要用到@Caching。
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)
3.5 @CacheConfig
與前面的緩存註解不同,這是一個類級別的註解。
如果類的所有操作都是緩存操作,你可以使用@CacheConfig來指定類,省去一些配置。
@CacheConfig("books")
public class BookRepositoryImpl implements BookRepository {
@Cacheable
public Book findBook(ISBN isbn) {...}
}
4. 使用@Cacheabl緩存並在緩存方法裏面設置緩存時間
Spring緩存註解使用EhCache,配置cache的緩存時間都是通過cache標籤的timeToLiveSeconds 屬性設置。如果想要在被緩存方法裏面設置緩存時間。
可以在當前類注org.springframework.cache.ehcache.EhCacheCacheManager
@Autowired
private EhCacheCacheManager ehCacheCacheManager;
org.springframework.cache.ehcache.EhCacheCacheManager這個類的作用是支持net.sf.ehcache.CacheManager。
具體代碼如下:
//1.通過org.springframework.cache.ehcache.EhCacheCacheManager獲取、//net.sf.ehcache.CacheManager
CacheManager cacheManager = ehCacheCacheManager.getCacheManager();
//2.獲取要設置緩存時間的cache類
Cache jsapiTicketCache = cacheManager.getCache("accessTokenCache");
//3.獲取cache類的配置類
CacheConfiguration cacheConfiguration = jsapiTicketCache.getCacheConfiguration();
//4.配置cache類的緩存時間
cacheConfiguration.setTimeToLiveSeconds(expiresIn);
5. 常見問題
5.1 Cacheable註解不生效原因
一個方法A調同一個類裏的另一個有緩存註解的方法B,這樣是不走緩存的。
爲什麼緩存沒有被正常創建??
因爲@Cacheable 是使用AOP 代理實現的 ,通過創建內部類來代理緩存方法,這樣就會導致一個問題,類內部的方法調用類內部的緩存方法不會走代理,不會走代理,就不能正常創建緩存,所以每次都需要去調用數據庫。