背景
在原有的项目中的一个工具类中,用到了cacheManager。
import net.sf.ehcache.CacheManager;
public class CacheHelper {
private static CacheManager cacheManager = (CacheManager) SpringContextTools.getBean("ehCacheManager");
....
}
这里用的cacheManager是ehcache的cacheManger,不是Spring中的org.springframework.cache.ehcache.EhCacheCacheManager。
使用的spring配置如下:
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:myEhcache.xml" />
</bean>
PS:在项目中只是使用了EhCache,并没有开启Spring的缓存注解。开启Spring缓存注解需要添加如下设置
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehCacheManager"/>
</bean>
<!-- 启用缓存注解开关 -->
<cache:annotation-driven cache-manager="cacheManager"/>
新项目
Maven设置
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
SpringBoot的配置类
新的项目使用SpringBoot,需要用到原项目中的工具类,于是创建一个配置类,用于创建EhCacheManager实例,提供给工具类使用。
@Configuration
public class CacheConfig {
/**
* 给CacheHelper用的cacheManager
*
* @param bean
* @return
*/
@Bean(name = "ehCacheManager")
public CacheManager cacheManager(EhCacheManagerFactoryBean bean) {
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("myEhcache.xml"));
cacheManagerFactoryBean.setShared(true);
return bean.getObject();
}
}
但是当使用bean.getObject()获取CacheManager时,总是取得null值。
PS: 在使用getObject()方法前手动调用afterPropertiesSet(),应该也可以解决null值问题。
查找问题
查看EhCacheManagerFactoryBean的源代码,发现属性cacheManager是在afterPropertiesSet()方法中被实例化。也就是说在SpringBoot项目的CacheConfig类中创建EhCacheManagerFactoryBean后,如果立即调用getObject(),这时cacheManager还没有被实例化,所以才会一直取得null值。
public class EhCacheManagerFactoryBean implements FactoryBean<CacheManager>, InitializingBean, DisposableBean {
......
@Override
public void afterPropertiesSet() throws CacheException {
......
if (this.shared) {
// Old-school EhCache singleton sharing...
// No way to find out whether we actually created a new CacheManager
// or just received an existing singleton reference.
this.cacheManager = CacheManager.create(configuration);
}
else if (this.acceptExisting) {
// EhCache 2.5+: Reusing an existing CacheManager of the same name.
// Basically the same code as in CacheManager.getInstance(String),
// just storing whether we're dealing with an existing instance.
synchronized (CacheManager.class) {
this.cacheManager = CacheManager.getCacheManager(this.cacheManagerName);
if (this.cacheManager == null) {
this.cacheManager = new CacheManager(configuration);
}
else {
this.locallyManaged = false;
}
}
}
else {
// Throwing an exception if a CacheManager of the same name exists already...
this.cacheManager = new CacheManager(configuration);
}
}
}
修改SpringBoot配置类
@Configuration
public class CacheConfig {
@Bean(name = "ehCacheManager")
public CacheManager cacheManager(EhCacheManagerFactoryBean bean) {
return bean.getObject();
}
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("myEhcache.xml"));
cacheManagerFactoryBean.setShared(true);
// 设置完属性后,cacheManagerFactoryBean会执行afterProertiesSet()方法,
// 所以不能在这里直接执行cacheManagerFactoryBean.getObject(),直接执行的话,因为在afterPropertiesSet()方法之前执行,所以:getObject()会得到null值
return cacheManagerFactoryBean;
}
}
修改后,可成功获取ehCacheManager。