数组的名称怎么自动增加_SpringBootCache源码解析:Cache自动配置

SpringBootCache源码解析

Spring Boot 支持了多种缓存的自动配置,其中包括 Generic、JCache、EhCache 2.x、Hazelcast、 Infinispan、 Couchbase、 Redis 、Caffeine 和 Simple。早期版本还支持Guava 的缓存,但目前已经废弃。本章将重点讲解缓存的自动配置 CacheAutoConfiguration和默认的 SimpleCacheConfiguration 自动配置及相关内容。

90d80ea4e6706e8fe32815c9e8d4bb34.png

Cache 简介

随着项目的发展,往往会出现- -些瓶颈, 比如与数据库的交互、与远程服务器的交互等。

此时,缓存便派上了用场。而在 Spring 3.1 中引入了基于注解的 Cache 的支持在spring-context 包 中 定 义 了 org.springframework.cache. CacheManager 和org.springframework.cache.Cache 接口,用来统一-不同的缓存的技术。

CacheManager 是 Spring 提供的各种缓存技术管理的抽象接口,而 Cache 接口包含缓存的增加、删除、读取等常用操作。针对 CacheManager, Spring 又提供了多种实现,比如基于Collection 来 实 现 的 SimpleCacheManager 、 基 于 ConcurrentHashMap 实 现 的Concurrent-MapCacheManager、基于 EhCache 实现的 EhCacheCacheManager 和基于JCache 标准实现的 JCacheCacheManager 等。

Spring Cache 的实现与 Spring 事务管理类似,都是基于 AOP 的方式。其核心思想是:第一次调用缓存方法时,会把该方法参数和返回结果作为键值存放在缓存中,当同样的参数再次请求方法时不再执行该方法内部业务逻辑,而是直接从缓存中获取结果并返回。

Spring Cache 提供了@CacheConfig、@Cacheable 、@CachePut 、@CacheEvict 等注解来完成缓存的透明化操作,相关功能如下。.@CacheConfig:用于类上,缓存一些公共设置。

.@Cacheable:用于方法上,根据方法的请求参数对结果进行缓存,下次读取时直接读取缓存内容。

.@CachePut: 用于方法上,能够根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用。

.@CacheEvict: 用于方法上,清除该方法的缓存,用在类上清除整个类的方法的缓存。

在了解了 Spring Cache 的基本作用的和定义之后,下面来看在 SpringBoot 中是如何对Cache 进行自动配置的。

940b3bf56f00bc32b1ba8de29baf9238.png

Cache 自动配置

在 Spring Boot 中,关于 Cache 的默认自动配置类只有 CacheAutoConfiguration,主要用于缓存抽象的自动配置,当通过@EnableCaching 启用缓存机制时,根据情况可创建CacheManager。 对于缓存存储可以通过配置自动检测或明确指定。

CacheAutoConfiguration 同样在 ME TA-INF/spring.factories 文件中配置注册。

# . Auto Configureorg. springframework. boot. autoconfigure . EnableAutoConfiguration=org. springframework . boot . autoconfigure . cache . CacheAutoConfiguration, 下面先来看 CacheAutoConfiguration 类的注解部分代码实现。@Configuration(proxyBeanMethods = false)@ConditionalOnClass (CacheManager. class)@ConditionalOnBeanCacheAspectSupport . class)@ConditionalOnMissingBean(value = CacheManager .class, name = "cacheResolver")@EnableConfigurationProperties (CacheProperties. class)@AutoConfigureAfter({ CouchbaseAutoConfiguration. class, HazelcastAutoConfiguration. class,HibernateJpaAutoConfiguration. class, RedisAutoConfiguration.class })@Import(CacheConfigurat ionImportSelector.class)public class CacheAutoConfiguration {}

@ConditionalOnClass 指 定 需 要 在 classpath 下 存 在 CacheManager 类 。 关 于CacheManager 类是一个缓存管理器的接口,管理各种缓存(Cache) 组件。针对不同的缓存技术,会有不同的实现类。比如,在 Spring 中提供了 SimpleCacheManager (测试)、Concurrent-MapCacheManager ( 默 认 ) 、 NoOpCacheManager ( 测 试 ) 、EhCacheCacheManager ( 基于 EhCache)、RedisCacheManager (基于 Redis) 等实现类。CacheManager 接口提供了两个方法:根据名称获取缓存和获取缓存名称集合,相关代码如下。

public interface CacheManager {//根据名称获取缓存@NullableCache getCache(String name);//获取缓存名称集合Collection getCacheNames();}

在 CacheManager 接 口 中 只 定 义 了 上 面 两 个 方 法 , 但 在 其 抽 象 实 现 类AbstractCache-Manager 中便扩展了新增 Cache、更新 Cache 等方法。

@ConditionalOnBean 指定需要存在 CacheAspectSupport 的 Bean 时才生效,换句话说,就 是 需要在使用 了 @EnableCaching 时 才 有 效 。 这 是 因 为 该 注 解 隐 式 的 导 致 了CacheInter-ceptor 对应的 Bean 的初始化,而 CacheInterceptor 为 CacheAspectSupport的子类。

@ConditionalOnMissingBean 指定名称为 cacheResolver 的 CacheManager 对象不存在时生效。

@EnableConfigurationProperties 加 载 缓 存 的 CacheProperties 配 置 项 , 配 置 前 缀 为spring.cache.

@AutoConfigureAfter 指定该自动配置必须在缓存数据基础组件自动配置之后进行,这里包括 Couchbase、 Hazelcast、 HibernateJpa 和 Redis 的自动配置

想要实现缓存,需要先集成对应的缓存框架或组件。这里以 Redis 为例,它的自动配置类RedisAutoConfiguration 中 便 完 成 了 Redis 相 关 的 Redis Template 和 StringRedisTemplate 的实例化。而 RedisAutoConfiguration 中导入类 JedisConnectionConfiguration又完成了 Redis 使用 Jedis 连接的配置

@Ilmport 导入 CacheConfigurationlmportSelector,其实是导入符合条件的 Spring Cache 使用的各类基础缓存框架(或组件)的配置。该类的实现就位于 CacheAutoConfiguration 中,代码如下。

static class CacheConfigurat ionImportSelector implements ImportSelector {public String[] selectImports(Annotat ionMetadata importingClassMetadata)CacheType[] types = CacheType.values();for(inti=0:i<1t cacheconfigurations . getconfigurat ionclass imports>1t>

导入类的获取是通过实现 ImportSelector 接口来完成的,具体获取步骤位于 selectlmports方法中。该方法中,首先获取枚举类 CacheType 中定义的缓存类型数据,CacheType 中定义支 持的缓存类型如下。

//支持的缓存类型(按照优先级定义)public enum CacheType {//使用上下文中的 Cache Bean 进行通用缓存GENERIC,// JCache(JSR- 107) 支持的缓存JCACHE,// EhCache 支持的缓存EHCACHE,// Hazelcast 支持的缓存HAZELCAST,// Infinispan 支持的缓存INFINISPAN,// Couchbase. 支持的缓存COUCHBASE,// Redis.支持的缓存REDIS,// Caffeine 支持的缓存CAFFEINE,//内存基本的简单缓存SIMPLE,// 不支持缓存NONE}

枚举类 CacheType 中定义了以上支持的缓存类型,而且上面的缓存类型默认是按照优先级从前到后的顺序排列的。

selectlmports 方法中,当获取 Cache Type 中定义的缓存类型数组之后,遍历该数组并通过CacheConfigurations 的 getConfigurationClass 方法获得每种类型缓存对应的自动配置类( 注解@Configuration 的类)。

CacheConfigurations 相关代码如下。

final class CacheConfigurations {private static final Map> MAPPINGS;//定义 CacheType 5@Conf iguration 之间的对应关系static {Map> mappings = new EnumMap<>(CacheType.class);mappings . put(CacheType . GENERIC, GenericCacheConfiguration.class);mappings . put(CacheType . EHCACHE,EhCacheCacheConfiguration. class);mappings . put (CacheType . HAZELCAST, HazelcastCacheConfiguration. class);mappings . put(CacheType . INF INISPAN, InfinispanCacheConfiguration.class);mappings . put (CacheType . JCACHE, JCacheCacheConfiguration. class);mappings . put (CacheType . COUCHBASE, CouchbaseCacheConfiguration. class);mappings . put (CacheType. REDIS, RedisCacheConfiguration.class);mappings . put(CacheType . CAFFEINE, CaffeineCacheConfiguration. class);mappings . put(CacheType . SIMPLE, SimpleCacheConfiguration.class);mappings . put(CacheType . NONE, NoOpCacheConfiguration.class);MAPPINGS = Collections . unmodifiableMap(mappings);//根据 CacheType型获得对应的@Configuration 类static String getConfigurationClass(CacheType cacheType) {Class> configurationClass = MAPPINGS . get(cacheType);Assert.state(configurationClass != null, () -> "Unknown cache type ”+cacheType) ;return configurationClass . getName();}}

经过以上步骤,我们会发现通过@Import 注解,CacheAutoConfiguration 导入了 CacheType中定义的所有类型的自动配置,也就是 Spring Boot 目前支持的缓存类型。而具体会自动配置哪种类型的缓存,还需要看导入的自动配置类里面的生效条件。

我们以 GenericCacheConfiguration 为例进行了解,源代码如下。

@Configurat ion(proxyBeanMethods = false)@ConditionalOnBean(Cache . class)@ConditionalOnMissingBean(CacheManager . class)@Conditional(CacheCondition. class)class GenericCacheConfiguration {@BeanSimpleCacheManager cacheManager(CacheManagerCustomizers customizers, Collection caches) {SimpleCacheManager cacheManager = new SimpleCacheManager();cacheManager . setCaches(caches);return customizers . customize(cacheManager);}}

在 GenericCacheConfiguration 的注解部分,@ConditionalOnBean 指定当 Cache 的 Bean存在时进行实例化操作,@ConditionalOnMissingBean 指定当 CacheManager 的 Bean 不存在时进行实例化操作,@Conditional 指定当满足 CacheCondition 指定的条件时进行实例化操作。

CacheManager 我们前面已经介绍过,不再赘述。Cache 是一 个定义了缓存通用操作的接口,其中定义了缓存名称获取、缓存值获取、清除缓存、添加缓存值等操作。对应的缓存组件或框架实现该接口,并根据组件自身的情况提供对应的操作方法实现。

下面看 CacheCondition 类中定义的条件。

class CacheCondition extends SpringBootCondition {@Overridepublic ConditionOutcome getMatchOutcome (ConditionContext context, Annotated-TypeMetadata metadata) {String sourceClass =if (metadata instanceof ClassMetadata) {sourceClass = ((ClassMetadata) metadata). getClassName() ;Condit ionMessage . Builder message = ConditionMessage . forCondition("Cache" ,sourceClass);Environment environment = context . getEnvironment( ) ;try {//创建指定环境的 Binder, 然后绑定属性到对象上BindResult specified = Binder . get( environment) . bind("spring.cache. type", CacheType . class);//如果未绑定,则返回匹配if (!specified. isBound()) {return ConditionOutcome . match(message . because("automatic cache type"));//获取所需的缓存类型CacheType required = CacheConfigurations . getType(((AnnotationMetadata)metadata) . getClassName());//如果已绑定,并且绑定的类型与所需的缓存类型相同,则返回匹配if (specified.get() == required) {return Conditi onOutcome . match(message. because(specified. get() +”cache type"));} catch (BindException ex) {//其他情况则返回不匹配return ConditionOutcome . noMatch(message . because("unknown cache type"));}}

CacheCondition 的核心逻辑就是首先通过 Binder 进行指定属性和类的绑定,然后通过绑定结果( BindResult)进行判断:如果判断结果是未绑定,则直接返回条件匹配;否则,判断绑定的缓存类型与所需的缓存类型是否相等,如果相等则返回条件匹配;其他情况则返回条件不匹配。

当 GenericCacheConfiguration 满足注解指定的条件后,便会通过 cacheManager 方法进行SimpleCacheManager 类的实例化操作。首先创建 SimpleCacheManager 对象,然后将缓存 集 合 设 置 到 对 象 中 , 最 后 通 过 CacheManagerCustomizers 的 customize 方 法 对SimpleCacheManager 进行定制化处理。

SimpleCacheManager 类是接口 CacheManager 的一个实现类,通过集合来实现缓存功能,源代码如下。

public class SimpleCacheManager extends AbstractCacheManager {private Collection extends Cache> caches = Collections . emptySet();//设置缓存集合public void setCaches (Collection extends Cache> caches) {this.caches = caches;//获取缓存集合@Overrideprotected Collection extends Cache> loadCaches() {return this. caches;}}

通过以上代码可以看出,SimpleCacheManager 的实现极其简单, 就是基于 Cache 的集合来实现的,它提供了设置缓存集合和获取缓存集合的方法。同样,由于实现比较简单,它往往被用于测试环境和简单缓存场景中。

上面我们以 GenericCacheConfiguration 为例讲解了@Import 引入的缓存组件配置,关于其他的类型缓存注解的配置就不再一-讲解了。

下 我 继 看 @Ilmport 的 CacheManagerEntityManagerFactoryDependsOnPostProcess-or类。该类同样为 CacheAutoConfiguration 的内部类。

@ConditionalOnClass(LocalContainerEnt ityManagerFactoryBean. class)@Conditiona lOnBean(AbstractEntityManagerFactoryBean.class)static class CacheManagerEntityManagerFactoryDependsOnPostProcessorextends EntityManagerFactoryDependsOnPostProcessor {CacheManagerEntityManagerFactoryDependsOnPostProcessor() {super("cacheManager");}}

该 类 实 现 了 EntityManagerFactoryDependsOnPostProcessor, 本质上是BeanFactoryPost-Processor 的 一 个 实 现 类 。 当 classpath中存在LocalContainerEntityManagerFactoryBean类和实现了抽象类AbstractEntityManagerFactoryBean 的类的 Bean 时,才会进行实例化操作。

在该类的构造方法中调用父类构造方法并传递值"cacheManager”。因此,动态声明了所有类型为 EntityManagerFactory 的 Bean 都必须依赖于名称为 cacheManager 的 Bean。

83accc1e14f306d7ed1b910c428d3ec4.png

最后,我们看一下 CacheAutoConfiguration 中其余的代码。

//实例化 CacheManagerCus tomizers@Bean@ConditionalOnMissingBeanpublic CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider> customizers) {return new CacheManagerCustomizers(customi zers . orderedStream(). collect(Collectors . toList()));}

cacheManagerCustomizers 方法初始化了 CacheManagerCustomizers 对象的 Bean,主要是 将 容 器 中 存 在 的 一 一 个 或 多 个 CacheManagerCustomizer 的 Bean 组 件 包 装 为CacheManager-Customizers,并将 Bean 注入容器。

//实例化 CacheManagerVal idator@Beanpublic CacheManagerValidator cacheAutoConfigurat ionValidator(CacheProperties-cacheProperties,objectProvider cacheManager) {return new CacheManagerValidator(cacheProperties, cacheManager);// CacheManagerVal idator 的具体定义,用于检查并抛出有意义的异常 static classCacheManagerValidator implements InitializingBean {private final CacheProperties cacheProperties;private final objectProvider cacheManager;CacheManagerValidator(CacheProperties cacheProperties, objectProviderkCache-Manager> cacheManager) {this. cacheProperties = cacheProperties;this. cacheManager = cacheManager;}@Overridepublic void afterPropertiesSet() {Assert . notNull(this . cacheManager . getIfAvailable(),) -> "No cache manager could be auto- configured, checkyour configuration (caching ”+ "type is” + this. cacheProperties .getType() + "')");}}

cacheAutoConfigurationValidator 方法初始化了 CacheManagerValidator 的 Bean,该 Bean用于确保容器中存在一个 CacheManager 对象, 以达到缓存机制可以继续被配置和使用的目的,同时该 Bean 也用来提供有意义的异常声明。

至此关于 Spring Boot 中 cache 的 CacheAutoConfiguration 自动配置讲解完毕,随后我们会继续讲一下Spring Boot 中默认的自动配置。

本文给大家讲解的内容是SpringBootCache源码解析:Cache自动配置

  1. 下篇文章给大家讲解的是SpringBootCache源码解析:默认Cache配置;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值