@Cacheable注解式緩存使用的要點:正確的注解式緩存配置,注解對象為spring管理的hean,調用者為另一個對象。有些情形下注解式緩存是不起作用的:同一個bean內部方法調用,子類調用父類中有緩存注解的方法等。后者不起作用是因為緩存切面必須走代理才有效,這時可以手動使用CacheManager來獲得緩存效果。
使用注解式緩存的正確方式:
<cache:annotation-driven cache-manager="springCacheManager" proxy-target-class="false"/>
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="cacheManagerName" value="ehcache"/>
</bean>
<bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
要點:@Cacheable(value="必須使用ehcache.xml已經定義好的緩存名稱,否則會拋異常")
@Component
public class CacheBean {
@Cacheable(value="passwordRetryCache",key="#key")
public String map(String key) {
System.out.println("get value for key: "+key);
return "value: "+key;
}
public String map2(String key) {
return map(key);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:cache.xml" })
public class CacheTester {
@Autowired CacheManager cacheManager;
@Autowired CacheBean cacheBean;
@Test public void cacheManager() {
System.out.println(cacheManager);
}
@Test public void cacheAnnotation() {
cacheBean.map("a");
cacheBean.map("a");
cacheBean.map("a");
cacheBean.map("a");
System.out.println(cacheManager.getCacheNames());
}
}
輸出:
get value for key: a
[authorizationCache, authenticationCache, shiro-activeSessionCache, passwordRetryCache]
稍微改造一下,讓ehcache支持根據默認配置自動添加緩存空間,這里提供自定義的MyEhCacheCacheManager即可
<bean id="springCacheManager" class="com.itecheast.ite.domain.util.MyEhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManager"/>
</bean>
另一種改造方式,找不到已定義的緩存空間時不緩存,或者關閉全部緩存。把cacheManagers配置去掉就可以關閉圈閉緩存。
<bean id="springCacheManager" class="org.springframework.cache.support.CompositeCacheManager">
<property name="cacheManagers">
<list>
<bean class="org.springframework.cache.ehcache.EhCacheCacheManager"></bean>
<!-- <bean class="com.itecheast.ite.domain.util.MyEhCacheCacheManager"></bean> 這個會自動創建緩存空間 -->
</list>
</property>
<property name="fallbackToNoOpCache" value="true"/>
</bean>
調用相同類或父類方法沒有緩存效果:這時可以選擇手動使用CacheManager。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:cache.xml" })
public class CacheTester {
@Test public void cacheAnnotation() {
this.map("a");
this.map("a");
}
@Cacheable(value="passwordRetryCache",key="#key")
public String map(String key) {
System.out.println("get value for key: "+key);
return "value: "+key;
}
}
或者再換一種方式:手動使用代理方式調用同類方法也是可以的
public class CacheBean {
@Autowired ApplicationContext applicationContext;
@Cacheable(value="passwordRetryCache",key="#key")
public String map(String key) { //方法不能為private,否則也沒有緩存效果
System.out.println("get value for key: "+key);
return "value: "+key;
}
public String map2(String key) {
CacheBean proxy = applicationContext.getBean(CacheBean.class);
return proxy.map(key); //這里使用proxy調用map就可以緩存,而直接調用map則沒有緩存
}
}
本文轉自《https://www.xlongwei.com/detail/-cacheable%E6%B3%A8%E8%A7%A3%E5%BC%8F%E7%BC%93%E5%AD%98%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8%E7%9A%84%E6%83%85%E5%BD%A2》