【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(二)

简介: 【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南

【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache功能的开发实战指南(一)https://developer.aliyun.com/article/1471011


配置文件结合Bean装配


@Value("${caffeine.spec}")
    private String caffeineSpec;
    @Bean(name = "caffeineSpec")
    public CacheManager cacheManagerWithCaffeineFromSpec(){
      CaffeineSpec spec = CaffeineSpec.parse(caffeineSpec);
      Caffeine caffeine = Caffeine.from(spec);  // 或使用 Caffeine caffeine = Caffeine.from(caffeineSpec);
      CaffeineCacheManager cacheManager = new CaffeineCacheManager();
      cacheManager.setCaffeine(caffeine);
      cacheManager.setCacheNames(getNames());
      return cacheManager;
    }

实现CacheLoader

CacheLoader是cache的一种加载策略,key不存在或者key过期之类的都可以通过CacheLoader来自定义获得/重新获得数据。使用refreshAfterWrite必须要设置cacheLoader

java

复制代码

@Configuration
    public class CacheConfig {
        @Bean
        public CacheLoader<Object, Object> cacheLoader() {
            CacheLoader<Object, Object> cacheLoader = new CacheLoader<Object, Object>() {
                @Override
                public Object load(Object key) throws Exception {
                    return null;
                }
                // 达到配置文件中的refreshAfterWrite所指定的时候回处罚这个事件方法
                @Override
                public Object reload(Object key, Object oldValue) throws Exception {
                    return oldValue; //可以在这里处理重新加载策略,本例子,没有处理重新加载,只是返回旧值。
                }
            };
            return cacheLoader;
        }
    }

CacheLoader实质是一个监听,处上述load与reload还包含,expireAfterCreate,expireAfterUpdate,expireAfterRead等可以很灵活的配置CacheLoader。

EhCache

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

导入依赖

引入springboot-cache和ehcache。需要注意,EhCache不需要配置version,SpringBoot的根pom已经集成了。

xml

复制代码

<dependency>
   <groupId>net.sf.ehcache</groupId>
   <artifactId>ehcache</artifactId>
</dependency>

加入配置:

properties

复制代码

spring.cache.type=ehcache # 配置ehcache缓存
spring.cache.ehcache.config=classpath:/ehcache.xml # 指定ehcache配置文件路径 ,可以不用写,因为默认就是这个路径,SpringBoot会自动扫描

ehcache配置文件

EhCache的配置文件ehcache.xml只需要放到类路径下面,SpringBoot会自动扫描。

xml

复制代码

<ehcache>
     
        <!--
            磁盘存储:指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个文件目录下
            path:指定在硬盘上存储对象的路径
            path可以配置的目录有:
                user.home(用户的家目录)
                user.dir(用户当前的工作目录)
                java.io.tmpdir(默认的临时目录)
                ehcache.disk.store.dir(ehcache的配置目录)
                绝对路径(如:d:\\ehcache)
            查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");
         -->
        <diskStore path="java.io.tmpdir" />
        <!--
            defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
            maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象
            eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期)
            timeToIdleSeconds:最大的发呆时间 /秒
            timeToLiveSeconds:最大的存活时间 /秒
            overflowToDisk:是否允许对象被写入到磁盘
            说明:下列配置自缓存建立起600秒(10分钟)有效 。
            在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。
            就算有访问,也只会存活600秒。
         -->
        <defaultCache maxElementsInMemory="10000" eternal="false"
                      timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" />
        <!-- 按缓存名称的不同管理策略 -->
        <cache name="myCache" maxElementsInMemory="10000" eternal="false"
                      timeToIdleSeconds="120" timeToLiveSeconds="600" overflowToDisk="true" />
     
    </ehcache>

装配

SpringBoot会为我们自动配置 EhCacheCacheManager 这个Bean,如果想自定义设置一些个性化参数时,通过Java Config形式配置。

java

复制代码

@Configuration
    @EnableCaching
    public class CacheConfig {  
     
        @Bean
        public CacheManager cacheManager() {
            return new EhCacheCacheManager(ehCacheCacheManager().getObject());
        }  
        @Bean
        public EhCacheManagerFactoryBean ehCacheCacheManager() {
            EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
            cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
            cmfb.setShared(true);
            return cmfb;
        }  
     
    }

Redis Cache

Redis 优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性
  • 分布式横向扩展

导入依赖

不需要spring-boot-starter-cache

xml

复制代码

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>

当你导入这一个依赖时,SpringBoot的CacheManager就会使用RedisCache。

Redis使用模式使用pool2连接池,在需要时引用下面的依赖

xml

复制代码

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.6.2</version>
    </dependency>

配置Redis

properties

复制代码

spring.redis.database=1 # Redis数据库索引(默认为0)
    spring.redis.host=127.0.0.1 # Redis服务器地址
    spring.redis.port=6379 # Redis服务器连接端口
    spring.redis.password= # Redis服务器连接密码(默认为空)
    spring.redis.pool.max-active=1000 # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.pool.max-wait=-1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.pool.max-idle=10 # 连接池中的最大空闲连接
    spring.redis.pool.min-idle=2 # 连接池中的最小空闲连接
    spring.redis.timeout=0 # 连接超时时间(毫秒)

如果你的Redis这时候已经可以启动程序了。

装配

如果需要自定义缓存配置可以通过,继承CachingConfigurerSupport类,手动装配,如果一切使用默认配置可不必

装配序列化类型

xml

复制代码

@Bean
        public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
            // 配置redisTemplate
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(connectionFactory);
            redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
            redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value序列化
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }

装配过期时间  

java

复制代码

/**
         * 通过RedisCacheManager配置过期时间
         *
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                    .entryTtl(Duration.ofHours()); // 设置缓存有效期一小时
            return RedisCacheManager
                    .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                    .cacheDefaults(redisCacheConfiguration).build();
        }

自定义缓存配置文件,继承 CachingConfigurerSupport

java

复制代码

/**
     *
     * Created by huanl on 2017/8/22.
     */
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport{
        public RedisConfig() {
            super();
        }
     
        /**
         * 指定使用哪一种缓存
         * @param redisTemplate
         * @return
         */
        @Bean
        public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
            RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
            return rcm;
        }
     
        /**
         * 指定默认的key生成方式
         * @return
         */
        @Override
        public KeyGenerator keyGenerator() {
           KeyGenerator keyGenerator = new KeyGenerator() {
               @Override
               public Object generate(Object o, Method method, Object... objects) {
                   StringBuilder sb = new StringBuilder();
                   sb.append(o.getClass().getName());
                   sb.append(method.getName());
                   for (Object obj : objects) {
                       sb.append(obj.toString());
                   }
                   return sb.toString();
               }
           };
           return keyGenerator;
        }
     
        @Override
        public CacheResolver cacheResolver() {
            return super.cacheResolver();
        }
     
        @Override
        public CacheErrorHandler errorHandler() {
            return super.errorHandler();
        }
     
        /**
         * redis 序列化策略 ,通常情况下key值采用String序列化策略
         * StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。StringRedisSerializer
         * RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。JdkSerializationRedisSerializer
         * @param factory
         * @return
         */
        @Bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory){
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(factory);
     
    //        // 使用Jackson2JsonRedisSerialize 替换默认序列化
    //        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    //        ObjectMapper om = new ObjectMapper();
    //        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    //        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    //        jackson2JsonRedisSerializer.setObjectMapper(om);
    //
    //
    //        //设置value的序列化方式
    //        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    //        //设置key的序列化方式
    //        redisTemplate.setKeySerializer(new StringRedisSerializer());
    //        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    //        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
     
            //使用fastJson作为默认的序列化方式
            GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();
            redisTemplate.setDefaultSerializer(genericFastJsonRedisSerializer);
            redisTemplate.setValueSerializer(genericFastJsonRedisSerializer);
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(genericFastJsonRedisSerializer);
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.afterPropertiesSet();
     
            return redisTemplate;
     
        }
     
        /**
         * 转换返回的object为json
         * @return
         */
        @Bean
        public HttpMessageConverters fastJsonHttpMessageConverters(){
            // 1、需要先定义一个converter 转换器
            FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
            // 2、添加fastJson 的配置信息,比如:是否要格式化返回的json数据
            FastJsonConfig fastJsonConfig = new FastJsonConfig();
            fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
            // 3、在convert 中添加配置信息
            fastConverter.setFastJsonConfig(fastJsonConfig);
            // 4、将convert 添加到converters当中
            HttpMessageConverter<?> converter = fastConverter;
            return new HttpMessageConverters(converter);
        }
     
    }
相关文章
|
安全 Java 数据库
Spring Security 实战指南:从入门到精通
本文详细介绍了Spring Security在Java Web项目中的应用,涵盖登录、权限控制与安全防护等功能。通过Filter Chain过滤器链实现请求拦截与认证授权,核心组件包括AuthenticationProvider和UserDetailsService,负责用户信息加载与密码验证。文章还解析了项目结构,如SecurityConfig配置类、User实体类及自定义登录逻辑,并探讨了Method-Level Security、CSRF防护、Remember-Me等进阶功能。最后总结了Spring Security的核心机制与常见配置,帮助开发者构建健壮的安全系统。
2685 0
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
469 1
Redis专题-实战篇二-商户查询缓存
|
11月前
|
缓存 并行计算 监控
vLLM 性能优化实战:批处理、量化与缓存配置方案
本文深入解析vLLM高性能部署实践,揭秘如何通过continuous batching、PagedAttention与前缀缓存提升吞吐;详解批处理、量化、并发参数调优,助力实现高TPS与低延迟平衡,真正发挥vLLM生产级潜力。
2706 0
vLLM 性能优化实战:批处理、量化与缓存配置方案
|
11月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
869 2
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
440 32
|
存储 缓存 安全
Go语言实战案例-LRU缓存机制模拟
本文介绍了使用Go语言实现LRU缓存机制的方法。LRU(最近最少使用)是一种常见缓存淘汰策略,当缓存满时,优先删除最近最少使用的数据。实现中使用哈希表和双向链表结合的方式,确保Get和Put操作均在O(1)时间内完成。适用于Web缓存、数据库查询优化等场景。
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
1815 8
|
存储 缓存 NoSQL
Spring Cache缓存框架
Spring Cache是Spring体系下的标准化缓存框架,支持多种缓存(如Redis、EhCache、Caffeine),可独立或组合使用。其优势包括平滑迁移、注解与编程两种使用方式,以及高度解耦和灵活管理。通过动态代理实现缓存操作,适用于不同业务场景。
869 0