NOTE
2.49 原理分析
缓存管理和缓存类是怎么生成的 1. spring-boot-starter预先导入的自动配置类 - @CacheAutoConfiguration cache自动配置的类在于CacheAutoConfiguration,他导入了一个CacheConfigurationImportSelector 我
这是历史学习笔记,可能存在过时或不完整的理解。
缓存管理和缓存类是怎么生成的
1. spring-boot-starter预先导入的自动配置类
- @CacheAutoConfiguration cache自动配置的类在于CacheAutoConfiguration,他导入了一个CacheConfigurationImportSelector
@Configuration
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)//导入了一些组件
public class CacheAutoConfiguration {
}
我们知道spring boot启动的时候需要refresh容器,其中有一个步骤会调用所有BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法,他会获取所有的ImportSelector,调用其selectImport方法,因此我们主要看CacheConfigurationImportSelector的selectImport方法
1.1. 默认导入SimpleCacheConfiguration缓存配置类
- CacheConfigurationImportSelector
static class CacheConfigurationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//获取所有预先定义的cache组件的枚举值
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
//遍历枚举,从CacheConfigurations定义的【cache组件名:cache配置类】获取相应的配置类
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
//所有的cache配置类如下
//0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
//1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
//2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
//3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
//4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
//5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
//6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
//7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
//8 = "org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration"
//9 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"//配置文件中开启debug=true发现默认是这个
//10 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"
return imports;
}
}
1.2. 向容器中导入ConcurrentMapCacheManager缓存管理器
我们以org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration为例
@Configuration
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {
private final CacheProperties cacheProperties;
private final CacheManagerCustomizers customizerInvoker;
SimpleCacheConfiguration(CacheProperties cacheProperties,
CacheManagerCustomizers customizerInvoker) {
this.cacheProperties = cacheProperties;
this.customizerInvoker = customizerInvoker;
}
//作用就是给ioc容器注入了ConcurrentMapCacheManager
@Bean
public ConcurrentMapCacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
cacheManager.setCacheNames(cacheNames);
}
return this.customizerInvoker.customize(cacheManager);
}
}
1.2.1. 通过缓存管理器获取缓存类
是个Map,key为cacheName,value为Cache【其实也是一个Map】
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
//把Cache类保存进ConcurrentHashMap,真正的缓存数据实在Cache类里
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
public ConcurrentMapCacheManager() {
}
@Override
public Cache getCache(String name) {
//从ConcurrentMap获取cache
Cache cache = this.cacheMap.get(name);
//如果为空,那么创建新的Cache并放入ConcurrentMap
if (cache == null && this.dynamic) {
//这里加了锁
synchronized (this.cacheMap) {
//重复检测??
cache = this.cacheMap.get(name);
if (cache == null) {
//创建cache实例
cache = createConcurrentMapCache(name);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
//使用的是ConcurrentMapCache
return new ConcurrentMapCache(name, new ConcurrentHashMap<Object, Object>(256),
isAllowNullValues(), actualSerialization);
}
}
1.2.2. 缓存类的操作
public class ConcurrentMapCache extends AbstractValueAdaptingCache {
private final String name;
//依旧使用的ConcurrentMap作为缓存数据的容器
private final ConcurrentMap<Object, Object> store;
private final SerializationDelegate serialization;
protected ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store,
boolean allowNullValues, SerializationDelegate serialization) {
super(allowNullValues);
Assert.notNull(name, "Name must not be null");
Assert.notNull(store, "Store must not be null");
this.name = name;
this.store = store;
this.serialization = serialization;
}
//cache的操作基本就是map的操作
@Override
public void put(Object key, Object value) {
this.store.put(key, toStoreValue(value));
}
@Override
public void evict(Object key) {
this.store.remove(key);
}
@Override
public void clear() {
this.store.clear();
}
@Override
protected Object lookup(Object key) {
return this.store.get(key);
}
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
// Try efficient lookup on the ConcurrentHashMap first...
ValueWrapper storeValue = get(key);
if (storeValue != null) {
return (T) storeValue.get();
}
// No value found -> load value within full synchronization.
synchronized (this.store) {
storeValue = get(key);
if (storeValue != null) {
return (T) storeValue.get();
}
T value;
try {
value = valueLoader.call();
}
catch (Throwable ex) {
throw new ValueRetrievalException(key, valueLoader, ex);
}
put(key, value);
return value;
}
}
}
2. 代理类的生成
2.1. 开启缓存代理类配置
通过这个注解我们会导入一个CachingConfigurationSelector
- @EnableCaching
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(CachingConfigurationSelector.class)//导入了CachingConfigurationSelector
public @interface EnableCaching
{
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
CachingConfigurationSelector继承了AdviceModeImportSelector,我们想看AdviceModeImportSelector的selectImport方法
2.1.1. 向容器导入AutoProxyRegistrar和ProxyCachingConfiguration
- AdviceModeImportSelector.selectImports
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
//获取代理模式 默认是AdviceMode.PROXY
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
//调用CachingConfigurationSelector的selectImport方法
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//走这个
return getProxyImports();
case ASPECTJ:
return getAspectJImports();
default:
return null;
}
}
private String[] getProxyImports() {
List<String> result = new ArrayList<String>(3);
//导入了AutoProxyRegistrar和ProxyCachingConfiguration
result.add(AutoProxyRegistrar.class.getName());
result.add(ProxyCachingConfiguration.class.getName());
if (jsr107Present && jcacheImplPresent) {
result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
}
return StringUtils.toStringArray(result);
}
CachingConfigurationSelector主要的作用是导入AutoProxyRegistrar和ProxyCachingConfiguration,我们只需要研究完AutoProxyRegistrar这个类就能明白代理类怎么生成的
2.1.2. AutoProxyRegistrar向容器注入了用于生成代理对象的InfrastructureAdvisorAutoProxyCreator
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {//是一个ImportBeanDefinitionRegistrar ,关注其registerBeanDefinitions方法
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
//这段代码先容器中注入了InfrastructureAdvisorAutoProxyCreator
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isWarnEnabled()) {
String name = getClass().getSimpleName();
logger.warn(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}
InfrastructureAdvisorAutoProxyCreator这个类继承了AbstractAdvisorAutoProxyCreator,后者继承了AbstractAutoProxyCreator,原理同1.给容器中注入AspectJAnnotationAutoProxyCreator组件.md 关键就在于AbstractAutoProxyCreator的postProcessAfterInitialization方法,会在TestService的bean实例化->赋值->调用自定义初始化方法的时候调用,接着生成代理类返回
2.1.3. 代理对象拦截被代理方法的调用,进入缓存操作
代理类会调用CacheInterceptor这个拦截器,进入到ConcurrentMapCache类的操作
3. 总结
- spring启动的时候refresh context有个步骤invokeBeanFactoryPostProcessors,会调用所有BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法
- 其中有个ConfigurationClassPostProcessor,他的postProcessBeanDefinitionRegistry方法会解析所有**@Configuration类的@Import标签,调用ImportSelector的selectImport方法以及ImportBeanDefinitionRegistrar的registerBeanDefinitions方法**
- CacheAutoConfiguration的CacheConfigurationImportSelector就是其中一个ImportSelector,他的selectImport方法作用是导入SimpleCacheConfiguration配置类,进而生成ConcurrentMapCacheManager这个缓存管理类
- EnableCaching的CachingConfigurationSelector也是其中一个,他的selectImport方法作用是导入AutoProxyRegistrar
- spring启动的时候refresh context有个步骤registerBeanPostProcessors,会向容器注册所有BeanPostProcessor,AutoProxyRegistrar就是其中一个
- spring启动的时候refresh context有个步骤finishBeanFactoryInitialization,生成TestService的bean的时候,调用自定义初始化方法时会调用AutoProxyRegistrar的postProcessAfterBeanInitialization方法,这个方法会为TestService返回一个代理对象
- 当TestController调用TestService的方法的时候先经过代理类,代理类会调用CacheInterceptor这个拦截器,最终进入到ConcurrentMapCache类的操作
- 最后的ConcurrentMapCache类的操作如下 调用方法之前会用@Cacheable的cacheNames去ConcurrentMapCacheManager的getCache方法获取相应的Cache类,没有的话则创建 然后调用ConcurrentMapCache的lookup方法,key是在__CacheAspectSupport__的generateKey生成的
- SimpleKeyGenerator
public static Object generateKey(Object... params) {
//长度为0,new SimpleKey();
if (params.length == 0) {
return SimpleKey.EMPTY;
}
//长度为1,直接返回params
if (params.length == 1) {
Object param = params[0];
if (param != null && !param.getClass().isArray()) {
return param;
}
}
//组合所有params
return new SimpleKey(params);
}
发现没有的话会调用目标方法,并把结果放进ConcurrentMapCache的put方法,把null存进去
EnableXX的都是向容器导入BeanPostProcessor, XXXAutoconfiguration都是先容器导入@Configuration,进而@Bean