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 共享。

  • 相关阅读:
    bzoj3505 数三角形 组合计数
    cogs2057 殉国 扩展欧几里得
    cogs333 荒岛野人 扩展欧几里得
    bzoj1123 BLO tarjan求点双连通分量
    poj3352 road construction tarjan求双连通分量
    cogs1804 联合权值 dp
    cogs2478 简单的最近公共祖先 树形dp
    cogs1493 递推关系 矩阵
    cogs2557 天天爱跑步 LCA
    hdu4738 Caocao's Bridge Tarjan求割边
  • 原文地址:https://www.cnblogs.com/MaxElephant/p/8109084.html
Copyright © 2011-2022 走看看