zoukankan      html  css  js  c++  java
  • spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战

    SpringBoot + Redis +SpringSession 缓存之实战

    前言

    前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需要消耗一定时间的,就是从某种程度上讲短暂的缓存不一致依旧存在。
    所以,我就选择了集中式缓存,在 SpringBoot 工程中使用 Redis 进行缓存。

    个人参考案例

    个人博客 : https://zggdczfr.cn/
    个人参考案例(如果认可的话,麻烦给颗star) : https://github.com/FunriLy/springboot-study/tree/master/%E6%A1%88%E4%BE%8B10

    (一)Spring Boot + Redis

    1. 安装 Redis

    Redis 原本是不支持在 Window 操作系统安装运行的,但后来有了 Window 支持,放上链接(具体安装百度一下就有): https://github.com/MSOpenTech/redis/releases
    注意:建议使用 2.8+ 以上Reids版本,不然会与 SpringSeeeion 产生冲突!

    2. 添加依赖

    新建一个SpringBoot工程,配置MyBatis+Druid。在pom.xml文件中添加Redis缓存支持。

          <!-- 缓存依赖 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-cache</artifactId>
          </dependency>
          <!-- spring boot redis 依赖 -->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-redis</artifactId>
          </dependency>
    
    3. application.properties 配置

    有关于 Redis 配置参数:

    # Redis 配置(默认配置)
    # Redis 数据库索引(默认为0)
    spring.redis.database=0
    # Redis 服务器地址
    spring.redis.host=localhost
    # Redis 服务器端口
    spring.redis.port=6379
    # Redis 服务器密码(默认为空)
    spring.redis.password=
    # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.pool.max-active=8
    # 连接池中的最大空闲连接
    spring.redis.pool.max-idle=8
    # 连接池中的最小空闲连接
    spring.redis.pool.min-idle=0
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.pool.max-wait=-1
    # 设置连接超时
    spring.redis.timeout=0
    
    4. 关于 SpringBoot 缓存注解

    在支持 Spring Cache 的环境下,

    • @EnableCaching : 开启SpringBoot缓存策略,放在启动主类。
    • @CacheConfig(cacheNames = "XXX") : 设置一个名为”XXX”的缓存空间。
    • @Cacheable : Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。
    • @CacheEvict : 清除缓存。
    • @CachePut : @CachePut也可以声明一个方法支持缓存功能。使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
    5. 添加 Redis 配置类

    重要参考资料 : http://www.jianshu.com/p/a2ab17707eff
    这个类主要是为Redis添加序列化工具,这一点 SpringBoot 并没有帮我们封装好(或者我没有找到)。

    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
    
        @Value("${spring.redis.host}")
        private String host;
        @Value("${spring.redis.port}")
        private int port;
        @Value("${spring.redis.timeout}")
        private int timeout;
    
        @Bean
        public KeyGenerator wiselyKeyGenerator(){
            return 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();
                }
            };
        }
    
        @Bean
        public JedisConnectionFactory redisConnectionFactory(){
            JedisConnectionFactory factory = new JedisConnectionFactory();
            factory.setHostName(host);
            factory.setPort(port);
            factory.setTimeout(timeout);    //设置连接超时
            return factory;
        }
    
        @Bean
        public CacheManager cacheManager(RedisTemplate redisTemplate){
            RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
            cacheManager.setDefaultExpiration(10);  //设置 key-value 超时时间
            return cacheManager;
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
            StringRedisTemplate template = new StringRedisTemplate(factory);
            setSerializer(template);    //设置序列化工具,就不必实现Serializable接口
            template.afterPropertiesSet();
            return template;
        }
    
        private void setSerializer(StringRedisTemplate template){
            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);
            template.setValueSerializer(jackson2JsonRedisSerializer);
        }
    }
    
    其它

    其他代码就不累赘贴出来了,直接参考一下我的Github仓库 : https://github.com/FunriLy/springboot-study/tree/master/%E6%A1%88%E4%BE%8B10
    启动工程后,访问 http://localhost:8080/redis ,我们可以在控制台看到以下结果:

    没有走缓存!8b10aba26bd5402bbdad2584d8452f1f
    User{uuid='8b10aba26bd5402bbdad2584d8452f1f', name='张三', age=20}
    User{uuid='8b10aba26bd5402bbdad2584d8452f1f', name='张三', age=20}
    ====== 修改 Redis 缓存数据 ======
    User{uuid='8b10aba26bd5402bbdad2584d8452f1f', name='李四', age=18}
    User{uuid='8b10aba26bd5402bbdad2584d8452f1f', name='李四', age=18}
    

    补充:若还是不太了解的话,可以查看一下我的上一篇博客spring boot学习(十三)SpringBoot缓存(EhCache 2.x 篇),里面利用了Log4j的debug模式详细打印了执行过的SQL语句,或者利用Druid控制台来查看SQL语句的执行情况。

    (二)Spring Session

    分布式系统中,sessiong共享有很多的解决方案,其中托管到缓存中应该是最常用的方案之一。

    SpringSession 原理

    @EnableRedisHttpSession 这个注解创建了一个名为 springSessionRepositoryFilter 的 bean,负责替换 httpSession,同时由 redis 提供缓存支持。
    maxInactiveIntervalInSeconds:设置Session失效时间。使用Redis Session之后,原Boot的server.session.timeout属性不再生效。

    1. 添加 SpringSession 配置类
    @Configuration
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
    public class HttpSessionConfig {
        // 默认无配置
    }
    

     2. 添加验证的URL接口

        @Value("${server.port}")
        String port;
    
        @RequestMapping(value = "/session", method = RequestMethod.GET)
        public Object getSession(HttpServletRequest request){
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("SessionId", request.getSession().getId());
            map.put("ServerPort", "服务端口号为 "+port);
            return map;
        }
    

     同时启动两个相同的工程(比如:8080端口与9090端口),访问 http://localhost:8080/sessionhttp://localhost:9090/session
    我们可以得到以下结果:

    {"SessionId":"01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2","ServerPort":"服务端口号为 8080"}
    
    {"SessionId":"01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2","ServerPort":"服务端口号为 9090"}
    

     结果中的SessionId是一致的,却是由两个不同项目工程来提供服务。这样子,SpringSession 利用拦截器 Filter 帮我们在每个请求前进行了同步设置,达到了分布式系统中 session 共享。

  • 相关阅读:
    2021
    关于react,vue框架的搭建及bug处理
    centOS7使用
    git初探
    项目分享技术大会总结
    angular中的异常机制与异常之外的处理
    angluarjs中指令的使用方式
    Servlet知识总结
    有时候真的需要一点点改变
    story
  • 原文地址:https://www.cnblogs.com/MaxElephant/p/8109084.html
Copyright © 2011-2022 走看看