我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBootCache缓存概念讲解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBootCache缓存概念讲解

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

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

Spring Cache提供了@CacheConfig、@Cacheable、@CachePut、@CacheEvict等注解来完成缓存的透明化操作,相关功能如下。

  • @CacheConfig:用于类上,缓存一些公共设置。
  • @Cacheable:用于方法上,根据方法的请求参数对结果进行缓存,下次读取时直接读取缓存内容。
  • @CachePut:用于方法上,能够根据方法的请求参数对其结果进行缓存,和@Cacheable不同的是,它每次都会触发真实方法的调用
  • @CacheEvict:用于方法上,清除该方法的缓存,用在类上清除整个类的方法的缓存。在了解了Spring Cache的基本作用的和定义之后,下面来看在Spring Boot中是如何对Cache进行自动配置的

Cache自动配置

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

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

下面先来看CacheAutoConfiguration类的注解部分代码实现。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
public class CacheAutoConfiguration { 
...
}

1、@ConditionalOnClass 指定需要在classpath下存在CacheManager类。

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

3、@ConditionalOnMissingBean指定名称为cacheResolver的CacheManager对象不存在时生效。@EnableConfigurationProperties加载缓存的CacheProperties配置项,配置前缀为spring.cache。

4、@EnableConfigurationProperties加载缓存的CacheProperties配置项,配置前缀为spring.cache。@AutoConfigureAfter指定该自动配置必须在缓存数据基础组件自动配置之后进行,这里包括Couchbase、Hazelcast、HibernateJpa和Redis的自动配置。

5、@Import导入CacheConfigurationImportSelector,其实是导入符合条件的Spring Cache使用的各类基础缓存框架(或组件)的配置。

ImportSelector

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;
    }
}

导入类的获取是通过实现ImportSelector接口来完成的,具体获取步骤位于selectImports方法中。该方法中,首先获取枚举类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中定义了以上支持的缓存类型,而且上面的缓存类型默认是按照优先级从前到后的顺序排列的。selectImports方法中,当获取CacheType中定义的缓存类型数组之后,遍历该数组并通过CacheConfigurations的getConfigurationClass方法获得每种类型缓存对应的自动配置类(注解@Configuration的类)。CacheConfigurations相关代码如下。

final class CacheConfigurations {
    private static final Map<CacheType, Class<?>> MAPPINGS;
    // 定义CacheType与@Configuration之间的对应关系
    static {
        Map<CacheType, Class<?>> 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.INFINISPAN, 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

// 实例化CacheManagerCustomizers
@Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(
        ObjectProvider<CacheManagerCustomizer<?>> customizers) {
    return new CacheManagerCustomizers(
            customizers.orderedStream().collect(Collectors.toList()));
}

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

CacheManagerValidator

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

// 实例化CacheManagerValidator
@Bean
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties-
cacheProperties,
        ObjectProvider<CacheManager> cacheManager) {
    return new CacheManagerValidator(cacheProperties, cacheManager);
}
// CacheManagerValidator的具体定义,用于检查并抛出有意义的异常
static class CacheManagerValidator implements InitializingBean {
    private final CacheProperties cacheProperties;
    private final ObjectProvider<CacheManager> cacheManager;
    CacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<Cache-
Manager> 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() + "')");
    }
}

Redis Cache

RedisCacheConfiguration

我们以RedisCacheConfiguration为例进行分析。源码如下

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
	@Bean
	RedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,
			ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
			ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
			RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
		RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
				determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
		}
		redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
		return cacheManagerCustomizers.customize(builder.build());
	}
	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));
	}
	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)));
		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;
	}
}

@ConditionalOnClass:当 RedisConnectionFactory 在存在时

@AutoConfigureAfter:在 RedisAutoConfiguration 之后加载

@ConditionalOnBean:RedisConnectionFactory 实例化之后

@ConditionalOnMissingBean:当 CacheManager 的 Bean 不存在时进行实例化操作

@Conditional:满足 CacheCondition 条件时,进行实例化操作

CacheCondition

class CacheCondition extends SpringBootCondition {
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, Annotated-
TypeMetadata metadata) {
        String sourceClass = "";
        if (metadata instanceof ClassMetadata) {
            sourceClass = ((ClassMetadata) metadata).getClassName();
        }
        ConditionMessage.Builder message = ConditionMessage.forCondition("Cache", 
sourceClass);
        Environment environment = context.getEnvironment();
        try {
            // 创建指定环境的Binder,然后绑定属性到对象上
            BindResult<CacheType> 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 ConditionOutcome.match(message.because(specified.get() + " cache type"));
            }
        } catch (BindException ex) {
        }
        // 其他情况则返回不匹配
        return ConditionOutcome.noMatch(message.because("unknown cache type"));
    }
}

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

RedisCacheManager

1、管理多个 RedisCache

2、每个 RedisCache 包含一个 name

3、每个 RedisCache 可以包含一个 RedisCacheConfiguration(可以有默认配置)

4、支持配置是否动态增加 Cache

public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
	private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
	private volatile Set<String> cacheNames = Collections.emptySet();
}
public class RedisCacheManager extends AbstractTransactionSupportingCacheManager {
    private final RedisCacheWriter cacheWriter;
    private final RedisCacheConfiguration defaultCacheConfig;
    private final Map<String, RedisCacheConfiguration> initialCacheConfiguration;
    private final boolean allowInFlightCacheCreation;
    protected Collection<RedisCache> loadCaches() {
        List<RedisCache> caches = new LinkedList();
        Iterator var2 = this.initialCacheConfiguration.entrySet().iterator();
        while(var2.hasNext()) {
            Entry<String, RedisCacheConfiguration> entry = (Entry)var2.next();
            caches.add(this.createRedisCache((String)entry.getKey(), (RedisCacheConfiguration)entry.getValue()));
        }
        return caches;
    }
    protected RedisCache getMissingCache(String name) {
        return this.allowInFlightCacheCreation ? this.createRedisCache(name, this.defaultCacheConfig) : null;
    }
    public Map<String, RedisCacheConfiguration> getCacheConfigurations() {
        Map<String, RedisCacheConfiguration> configurationMap = new HashMap(this.getCacheNames().size());
        this.getCacheNames().forEach((it) -> {
            RedisCache cache = (RedisCache)RedisCache.class.cast(this.lookupCache(it));
            configurationMap.put(it, cache != null ? cache.getCacheConfiguration() : null);
        });
        return Collections.unmodifiableMap(configurationMap);
    }
    protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
        return new RedisCache(name, this.cacheWriter, cacheConfig != null ? cacheConfig : this.defaultCacheConfig);
    }
}

RedisCache

public class RedisCache extends AbstractValueAdaptingCache {
    private static final byte[] BINARY_NULL_VALUE;
    private final String name;
    private final RedisCacheWriter cacheWriter;
    private final RedisCacheConfiguration cacheConfig;
    private final ConversionService conversionService;
}

RedisCache 的特点

1、key 支持非 String 类型,比如 Map 和 Collection

2、RedisCacheWriter 是更底层的实现,RedisCache 对 RedisCacheWriter 进行封装。

3、通过 ConversionService 对 key 进行转换

RedisCacheWriter

通过 RedisConnectionFactory 取一个 RedisConnection,然后执行命令。putIfAbsent 支持分布式锁。

到此这篇关于SpringBoot Cache缓存概念讲解的文章就介绍到这了,更多相关SpringBoot Cache内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBootCache缓存概念讲解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBootCache缓存概念讲解

这篇文章主要介绍了Springbootcache缓存,使用缓存最关键的一点就是保证缓存与数据库的数据一致性,本文给大家介绍最常用的缓存操作模式,对Springbootcache缓存操作流程感兴趣的朋友一起看看吧
2022-12-30

缓存的基础概念解读

高速缓存(Cache,简称缓存),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种RAM,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。Cache是位于CPU和DRAM之间,通常由SRAM构成的规模小存
2023-06-04

C++内存模型与名称空间概念讲解

这篇文章主要介绍了C++内存模型与名称空间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-01-02

MySQL中Like概念及用法讲解

Like中文解释为喜欢的意思,但当应用于MySQL数据库中,Like则是一种语句,用于模糊查询,主要是针对字符型字段的,在一个字符型字段列中检索包含对应子串的。本文向大家介绍MySQL中Like语句。 一、Like是什么意思 1、Like算
2022-05-30

ASP.NET缓存机制基础概念是什么

这篇文章主要讲解了“ASP.NET缓存机制基础概念是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ASP.NET缓存机制基础概念是什么”吧!ASP.NET缓存机制名词解释页输出缓存:保存
2023-06-18

Java中StringUtils与CollectionUtils和ObjectUtil概念讲解

这篇文章主要介绍了Java中StringUtils与CollectionUtils和ObjectUtil概念,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-27

bloom filter概念讲解以及代码分析

Bloom filter 优点就是它的插入和查询时间都是常数,另外它查询元素却不保存元素本身,具有良好的安全性
2022-11-15

C++特殊类设计概念与示例讲解

本文介绍C++中三种特殊类设计模式:单例模式、工厂模式和代理模式。通过详细讲解每种设计模式的实现原理和应用场景,帮助读者理解和掌握这些常用的面向对象设计模式,并提供示例代码和技巧,便于实际应用
2023-05-17

C语言哈希表概念超详细讲解

哈希是一种很高效的存储数据的结构,它是利用的一种映射关系,它也是STL中unordered_map和unordered_set 的底层结构。本文,主要讲解哈希的原理,哈希的实现,里面关键点在于如何解决哈希冲突
2023-02-09

C#Marshal类基本概念和入门实例讲解

这篇文章主要介绍了C#Marshal类基本概念和入门实例,具有很好的参考价值,希望对大家有所帮助。
2023-02-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录