cache在我开发应用过程最常用得工具,框架有 reids,ehcache. 或者 在代码中使用HashMap作为缓存.
spring-boot 使用 Cache 时非常简单的,引入依赖 ‘spring-boot-starter-cache’ 和启用注解 @EnableCaching注解,以及第三方jar 就可以使用.
这里研究下
1.为啥有了自动装配还开启注解才能使用呢?
2. 注解可以手动选择使用哪个缓存工具
带着问题研究才会更好.
先研究下 @EnableCaching
开关注解注解一般都时通过Import 加载配置类,这里是加载 CachingConfigurationSelector 类,其本质就是ImportSelect 接口,用于导入哪些Bean信息,从源代码:可以看出导入 AutoProxyRegistrar,ProxyCachingConfiguration
private String[] getProxyImports() {
List<String> result = new ArrayList<>(3);
result.add(AutoProxyRegistrar.class.getName());
result.add(ProxyCachingConfiguration.class.getName());
if (jsr107Present && jcacheImplPresent) {
result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
}
return StringUtils.toStringArray(result);
}
可以不难猜出,AutoProxyRegistrar 用于生成代理对象; ProxyCachingConfiguration 用于定义AOP拦截器Bean信息,CacheInterceptor bean. 改bean是CacheAspectSupport 实现类. 这个其实就是为啥要加注解的原因. 只有生成这个Bean,自动配置类才会生效,见CacheAutoConfiguration 分析
1.分析下 ProxyCachingConfiguration
这个类除了主要定义了AOP拦截器的bean,源码如下:我们看到拦截器可以 configure 进行设置缓存信息,这里我们就可以解决@EnableCaching 可以自主选择哪个缓存进行存储
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheInterceptor cacheInterceptor() {
CacheInterceptor interceptor = new CacheInterceptor();
interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
interceptor.setCacheOperationSource(cacheOperationSource());
return interceptor;
}
我们可以看到父类AbstractCachingConfiguration setConfigurers 方法.改方法是自动注入. 源码如下,这个方法主要设置AOP使用哪个缓存管理器
@Autowired(required = false)
void setConfigurers(Collection<CachingConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException(configurers.size() + " implementations of " +
"CachingConfigurer were found when only 1 was expected. " +
"Refactor the configuration such that CachingConfigurer is " +
"implemented only once or not at all.");
}
CachingConfigurer configurer = configurers.iterator().next();
useCachingConfigurer(configurer);
}
CacheAutoConfiguration
先看该类源码注解信息
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
我们可以看到@ConditionalOnBean(CacheAspectSupport.class) 这个条件,由此我们可以看必须要有CacheAspectSupport Bean才会生效,这个bean就是在启用注解开关才会生效.,其他的条件一般跟配置文件和是否引入第三方jar.
CacheConfigurationImportSelector 这也是 ImportSelector,用于选择导入哪些配置类,一共支持的类型可以查看 CacheType 枚举类. 我们可以看出支持好多种,最最基础 simple,使用ConcurrentMap 实现. 在开发的时候在没有第三方组件可以直接使用这个进行模拟测试.