<cache:annotation-driven />
<context:component-scan base-package='org.bk.samples.cachexml'></context:component-scan>
<bean id='cacheManager' class='org.springframework.cache.support.SimpleCacheManager'>
<property name='caches'>
<set>
<ref bean='defaultCache'/>
</set>
</property>
</bean>
<bean name='defaultCache' class='org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean'>
<property name='name' value='default'/>
</bean>
工厂bean ConcurrentMapCacheFactoryBean是一个依次负责创建Cache bean的bean。
我第一次尝试将此设置转换为@Configuration样式:
@Bean
public SimpleCacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<Cache>();
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
cacheFactoryBean.setName('default');
caches.add(cacheFactoryBean.getObject());
cacheManager.setCaches(caches );
return cacheManager;
}
但是,这没有用,原因是我在这里完全绕过了一些Spring bean生命周期机制。 事实证明,ConcurrentMapCacheFactoryBean还实现了InitializingBean接口,并在InitializingBean的'afterPropertiesSet'方法中对缓存进行了急切的初始化。 现在,通过直接调用factoryBean.getObject(),我完全绕过了afterPropertiesSet方法。
有两种可能的解决方案:
1.以与在XML中定义的相同方式定义FactoryBean:
@Bean
public SimpleCacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<Cache>();
caches.add(cacheBean().getObject());
cacheManager.setCaches(caches );
return cacheManager;
}
@Bean
public ConcurrentMapCacheFactoryBean cacheBean(){
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
cacheFactoryBean.setName('default');
return cacheFactoryBean;
}
在这种情况下,从@Bean方法返回一个显式的FactoryBean,Spring将负责在此bean上调用生命周期方法。
2.复制相关生命周期方法中的行为,在此特定实例中,我知道FactoryBean在afterPropertiesSet方法中实例化ConcurrentMapCache,我可以通过以下方式直接复制此行为:
@Bean
public SimpleCacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<Cache>();
caches.add(cacheBean());
cacheManager.setCaches(caches );
return cacheManager;
}
@Bean
public Cache cacheBean(){
Cache cache = new ConcurrentMapCache('default');
return cache;
}
将FactoryBean从xml转换为@Configuration时要记住的一点。
注意:
可以根据需要进行一页有效的测试:
package org.bk.samples.cache;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestSpringCache.TestConfiguration.class})
public class TestSpringCache {
@Autowired TestService testService;
@Test
public void testCache() {
String response1 = testService.cachedMethod('param1', 'param2');
String response2 = testService.cachedMethod('param1', 'param2');
assertThat(response2, equalTo(response1));
}
@Configuration
@EnableCaching
@ComponentScan('org.bk.samples.cache')
public static class TestConfiguration{
@Bean
public SimpleCacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<Cache> caches = new ArrayList<Cache>();
caches.add(cacheBean().getObject());
cacheManager.setCaches(caches );
return cacheManager;
}
@Bean
public ConcurrentMapCacheFactoryBean cacheBean(){
ConcurrentMapCacheFactoryBean cacheFactoryBean = new ConcurrentMapCacheFactoryBean();
cacheFactoryBean.setName('default');
return cacheFactoryBean;
}
}
}
interface TestService{
String cachedMethod(String param1,String param2);
}
@Component
class TestServiceImpl implements TestService{
@Cacheable(value='default', key='#p0.concat('-').concat(#p1)')
public String cachedMethod(String param1, String param2){
return 'response ' + new Random().nextInt();
}
}
参考: all和其他博客中来自我们JCG合作伙伴 Biju Kunjummen的Spring @Configuration和FactoryBean 。
翻译自: https://www.javacodegeeks.com/2012/08/spring-configuration-and-factorybean.html