相关阅读
简介
缓存管理的自动配置;
核心代码
@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 })
public class CacheAutoConfiguration {
/**
* 创建CacheManagerCustomizers Bean
* XxxCacheConfiguration中创建CacheManager时会用来装饰CacheManager
*/
@Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}
/**
* 创建CacheManagerValidator Bean
* 实现了InitializingBean,在afterPropertiesSet方法中校验CacheManager
*/
@Bean
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
ObjectProvider<CacheManager> cacheManager) {
return new CacheManagerValidator(cacheProperties, cacheManager);
}
/**
* 后置处理器
* 内部类,动态声明EntityManagerFactory实例需要依赖"cacheManager"实例
*/
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
super("cacheManager");
}
}
/**
* 缓存管理器校验器
* 内部类,实现了InitializingBean接口,实现afterPropertiesSet用于校验缓存管理器
*/
static class CacheManagerValidator implements InitializingBean {
private final CacheProperties cacheProperties;
private final ObjectProvider<CacheManager> cacheManager;
CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {
this.cacheProperties = cacheProperties;
this.cacheManager = cacheManager;
}
/**
* 当依赖注入后处理
*/
@Override
public void afterPropertiesSet() {
// 校验缓存管理器
Assert.notNull(this.cacheManager.getIfAvailable(),
() -> "No cache manager could be auto-configured, check your configuration (caching type is '"
+ this.cacheProperties.getType() + "')");
}
}
/**
* 缓存配置导入选择器
*/
static class CacheConfigurationImportSelector implements ImportSelector {
/**
* 选择导入
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
}
简析
借助Conditional
机制实现自动配置条件:
CacheManager.class
在类路径上存在;CacheAspectSupport
实例存在(即CacheInterceptor
);CacheManager
实例不存在,且cacheResolver
Bean不存在;
当满足以上要求时,就会触发SpringCache的自动配置逻辑,CacheAutoConfiguration
会引入其它的Bean,具体如下:- 通过@
EnableConfigurationProperties
使CacheProperties
生效; - 借助Import机制导入内部类:
CacheConfigurationImportSelector
和CacheManagerEntityManagerFactoryDependsOnPostProcessor
; - 创建了
CacheManagerCustomizers
、CacheManagerValidator
Bean;
CacheProperties
简介
用于接收缓存相关的配置参数;
核心代码
// 接收以"spring.cache"为前缀的配置参数
@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {
// 缓存实现类型
// 未指定,则由环境自动检测,从CacheConfigurations.MAPPINGS自上而下加载XxxCacheConfiguration
// 加载成功则检测到缓存实现类型
private CacheType type;
// 缓存名称集合
// 通常,该参数配置了则不再动态创建缓存
private List<String> cacheNames = new ArrayList<>();
private final Caffeine caffeine = new Caffeine();
private final Couchbase couchbase = new Couchbase();
private final EhCache ehcache = new EhCache();
private final Infinispan infinispan = new Infinispan();
private final JCache jcache = new JCache();
private final Redis redis = new Redis();
// getter and setter
...
/**
* Caffeine的缓存配置参数
*/
public static class Caffeine {
...
}
/**
* Couchbase的缓存配置参数
*/
public static class Couchbase {
...
}
/**
* EhCache的缓存配置参数
*/
public static class EhCache {
...
}
/**
* Infinispan的缓存配置参数
*/
public static class Infinispan {
...
}
/**
* JCache的缓存配置参数
*/
public static class JCache {
...
}
/**
* Redis的缓存配置参数
*/
public static class Redis {
// 过期时间,默认永不过期
private Duration timeToLive;
// 支持缓存空值标识,默认支持
private boolean cacheNullValues = true;
// 缓存KEY前缀
private String keyPrefix;
// 使用缓存KEY前缀标识,默认使用
private boolean useKeyPrefix = true;
// 启用缓存统计标识
private boolean enableStatistics;
// getter and setter
...
}
}
CacheConfigurationImportSelector
简介
CacheAutoConfiguration
的静态内部类,实现了ImportSelector
接口的selectImports
方法,导入Cache
配置类;
核心方法
/**
* 挑选出CacheType对应的配置类
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
// 遍历CacheType
for (int i = 0; i < types.length; i++) {
// 获取CacheType的配置类
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
CacheConfigurations
简介
维护了CacheType
和XxxCacheConfiguration
配置类的映射关系;
核心代码
/**
* CacheType和配置类的映射关系集合
* 无任何配置条件下,从上而下,默认生效为SimpleCacheConfiguration
*/
static {
Map<CacheType, String> mappings = new EnumMap<>(CacheType.class);
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName());
mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class.getName());
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName());
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName());
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName());
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName());
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName());
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName());
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName());
MAPPINGS = Collections.unmodifiableMap(mappings);
}
/**
* 根据CacheType获取配置类
*/
static String getConfigurationClass(CacheType cacheType) {
String configurationClassName = MAPPINGS.get(cacheType);
Assert.state(configurationClassName != null, () -> "Unknown cache type " + cacheType);
return configurationClassName;
}
/**
* 根据配置类获取CacheType
*/
static CacheType getType(String configurationClassName) {
for (Map.Entry<CacheType, String> entry : MAPPINGS.entrySet()) {
if (entry.getValue().equals(configurationClassName)) {
return entry.getKey();
}
}
throw new IllegalStateException("Unknown configuration class " + configurationClassName);
}
CacheType
简介
缓存类型的枚举,按照优先级定义;
核心代码
GENERIC // Generic caching using 'Cache' beans from the context.
JCACHE // JCache (JSR-107) backed caching.
EHCACHE // EhCache backed caching.
HAZELCAST // Hazelcast backed caching.
INFINISPAN // Infinispan backed caching.
COUCHBASE // Couchbase backed caching.
REDIS // Redis backed caching.
CAFFEINE // Caffeine backed caching.
SIMPLE // Simple in-memory caching.
NONE // No caching.
CacheCondition
简介
所有缓存配置使用的通用配置条件;
核心代码
/**
* 匹配逻辑
*/
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
String sourceClass = "";
if (metadata instanceof ClassMetadata) {
sourceClass = ((ClassMetadata) metadata).getClassName();
}
ConditionMessage.Builder message = ConditionMessage.forCondition("Cache", sourceClass);
Environment environment = context.getEnvironment();
try {
// 获取配置文件中指定的CacheType
BindResult<CacheType> specified = Binder.get(environment).bind("spring.cache.type", CacheType.class);
if (!specified.isBound()) {
// 不存在则根据CacheConfiguration.mappings自上而下匹配合适的CacheConfiguration
return ConditionOutcome.match(message.because("automatic cache type"));
}
CacheType required = CacheConfigurations.getType(((AnnotationMetadata) metadata).getClassName());
// 存在则比较CacheType是否一致
if (specified.get() == required) {
return ConditionOutcome.match(message.because(specified.get() + " cache type"));
}
}
catch (BindException ex) {
}
return ConditionOutcome.noMatch(message.because("unknown cache type"));
}
CacheManagerEntityManagerFactoryDependsOnPostProcessor
简介
动态声明EntityManagerFactory
实例需要依赖cacheManager
实例;
核心代码
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
extends EntityManagerFactoryDependsOnPostProcessor {
CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
// 动态声明EntityManagerFactory实例需要依赖"cacheManager"实例
super("cacheManager");
}
}
常见的CacheConfiguration
RedisCacheConfiguration
简介
Redis
缓存配置;
核心代码
// Bean方法不被代理
@Configuration(proxyBeanMethods = false)
// RedisConnectionFactory在类路径上存在
@ConditionalOnClass(RedisConnectionFactory.class)
// 在RedisAutoConfiguration之后自动配置
@AutoConfigureAfter(RedisAutoConfiguration.class)
// RedisConnectionFactory实例存在
@ConditionalOnBean(RedisConnectionFactory.class)
// CacheManager实例不存在
@ConditionalOnMissingBean(CacheManager.class)
// 根据CacheCondition选择导入
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
/**
* 创建RedisCacheManager
*/
@Bean
RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
// 使用RedisCachemanager
RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
List<String> cacheNames = cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
// 设置CacheProperties配置的值
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
if (cacheProperties.getRedis().isEnableStatistics()) {
// 设置CacheProperties配置的值
builder.enableStatistics();
}
// 装饰redisCacheManagerBuilder
redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
// 装饰redisCacheManager
return cacheManagerCustomizers.customize(builder.build());
}
/**
* 如果redisCacheConfiguration不存在则使用默认值
*/
private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
CacheProperties cacheProperties,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
ClassLoader classLoader) {
return redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties, classLoader));
}
/**
* 根据CacheProperties创建默认RedisCacheConfigutation
*/
private org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(
CacheProperties cacheProperties, ClassLoader classLoader) {
Redis redisProperties = cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
config = config.serializeValuesWith(
SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
// 优先使用CacheProperties的值,若存在的话
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
SimpleCacheConfiguration
简介
最简单的缓存配置,通常当作后备;
核心代码
// Bean方法不被代理
@Configuration(proxyBeanMethods = false)
// 不存在CacheManager实例
@ConditionalOnMissingBean(CacheManager.class)
// 根据CacheCondition选择导入
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {
/**
* 创建CacheManager
*/
@Bean
ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
CacheManagerCustomizers cacheManagerCustomizers) {
// 使用ConcurrentMapCacheManager
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
List<String> cacheNames = cacheProperties.getCacheNames();
// 如果CacheProperties配置了cacheNames,则使用
if (!cacheNames.isEmpty()) {
// 配置了cacheNames,则不支持动态创建缓存了
cacheManager.setCacheNames(cacheNames);
}
// 装饰ConcurrentMapCacheManager
return cacheManagerCustomizers.customize(cacheManager);
}
}