springboot源码探究3--springcache探究

springboot 使用缓存,最简单的做法:只需要在启动类配置(本篇博客只写源码探究,具体使用可自行百度)

  再在方法上写上下面的注解,就可以直接用了,通过debug调试可以发现,第二次触发,没有再走下面return的dao层的方法,返回的是缓存中的数据。

 究竟springboot做了什么,第一个想法是:之前有用过redis做缓存,缓存存放在redis,但是压根没有做相关redis配置 ,那应该就是用的内存做的缓存。

咱们下面就来探究一下,默认情况下spring究竟把数据缓存在了哪里。

通过点击 @EnableCaching 进入源码,可以看到,在 EnableCaching 在spring-context下。

  整个cache包,最外层有cachecacheManager,两个接口,看两个最外层的接口的实现类。

catche实现类如下:

  catcheManager实现类:

  大家应该知道,springboot框架,spring自己给我加了很多默认的配置,都在spring-boot-autoconfigure下,进入其源码下,可以看到如下

  都是springboot内置的缓存的配置项。从这里开始着手,是最方便的。

但是,我开始去找的时候也是一团乱麻,不知道该从何着手。并不是从这里开始的:

我的想法是既然要查缓存那么肯定会走:cache接口的查询接口,就一个个的debug试试呗,最终---->get(Object key)---->AbstractValueAdaptingCache 类

 然后继续debug进入,lookup,发现进入了ConcurrentMapCache,此时

1     @Override
2     @Nullable
3     protected Object lookup(Object key) {
4         return this.store.get(key);
5     }

看代码可以发现store就是一个map,那么这个map从哪里加载的?点击ConcurrentMapCache,查看调用者发现有catche的实现类

  继续找ConcurrentMapCacheManager调用者,发现SimpleCacheConfiguration配置项。

 到此为止,就能发现,springboot默认加载的是:SimpleCacheConfiguration。那么问题来了,为什么会加载SimpleCacheConfiguration,这是个问题,也困扰了我好一段时间。因为看

  默认配置有如上面很多个,究竟是怎么加载的,点击进去这些配置查看,多个配置代码都会爆红,有些代码在环境中不存在,那这些爆红的肯定都不会加载了。 从上面可以看到最终排除完,剩下

  

  NoOpCacheConfiguration和SimpleCacheConfiguration,只有这两个配置是不需要依赖别的什么就可以默认可以加载的,那究竟为什么加载了SimpleCacheConfiguration,这里困住我了,实在找不到。最终还是参考了前辈的博客https://www.jianshu.com/p/8a953cd0b265

困惑我的点,是在CacheAutoConfiguration配置中 

 引入CacheConfigurationImportSelector 的所有枚举CacheTyp,如下第八行代码是有顺序的。那么咱们就debug看看,是不是这样(不好意思,持有怀疑态度去面对前辈)

 1     static class CacheConfigurationImportSelector implements ImportSelector {
 2 
 3         @Override
 4         public String[] selectImports(AnnotationMetadata importingClassMetadata) {
 5             CacheType[] types = CacheType.values();
 6             String[] imports = new String[types.length];
 7             for (int i = 0; i < types.length; i++) {
 8                 imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
 9             }
10             return imports;
11         }
12 
13     }

上面代码根据CacheTyp获取所有的配置显示,一共包含了如下所有的配置信息

  跟随代码执行,进入processConfigurationClass,实现配置的方法 

 从上面说的,诸多配置打开,代码都是红色的就可以知道,这里前面配置都是需要跳过的,进入shouldSkip,基本都忽略了;

   

题外话:这里还有个有意思的需要探究的源码:@Conditional,在spring容器加载时候的实现的步骤,上面根据debug显示最终执行完剩下GenericCacheConfiguration,NoOpCacheConfiguration,SimpleCacheConfiguration。(有空再探究)

 直到倒数第二个 也就是SimpleCacheConfiguration

  到这里,咱们再细看一下,SimpleCacheConfiguration,如下,当前配置都还没有注入过CacheManager,所以此时SimpleCacheConfiguration复合要求

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CacheManager.class)//如果不存在CacheManager则加载
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {

	@Bean//注入一个ConcurrentMapCacheManager 也就是CacheManager
	ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
			CacheManagerCustomizers cacheManagerCustomizers) {
		ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			cacheManager.setCacheNames(cacheNames);
		}
		return cacheManagerCustomizers.customize(cacheManager);
	}

}

  从上面的代码看,SimpleCacheConfiguration驻入了ConcurrentMapCacheManager ,而NoOpCacheConfiguration的@ConditionalOnMissingBean(CacheManager.class),因为前面已经有了CacheManager就将不再被加载。

  要看上面的配置项可以在配置文件中加入debug=true,就可以看到spring框架加载的信息,帮助大家整理源码。

上面我用的源码探究的推导方式,就结束了是比较笨的方法。

大家可以直接从autoconfigure.cache,配置信息着手,并结合spring打印的日志信息进行推导。

上面文中化斜线的语句,是本次源码探究留下的疑问点,后续有时间探索一下,再分享出来给大家看。多谢观看本文

猜你喜欢

转载自www.cnblogs.com/wjweily/p/12589214.html