1. 程式人生 > >spring boot 學習(十四)SpringBoot+Redis+SpringSession緩存之實戰

spring boot 學習(十四)SpringBoot+Redis+SpringSession緩存之實戰

blog 安裝 user 個人 turn pid pass pin star

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/session 與 http://localhost:9090/session
我們可以得到以下結果:

{"SessionId":"01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2","ServerPort":"服務端口號為 8080"}

{"SessionId":"01f353e1-5cd3-4fbd-a5d0-9a73e17dcec2","ServerPort":"服務端口號為 9090"}

結果中的SessionId是一致的,卻是由兩個不同項目工程來提供服務。這樣子,SpringSession 利用攔截器 Filter 幫我們在每個請求前進行了同步設置,達到了分布式系統中 session 共享。

spring boot 學習(十四)SpringBoot+Redis+SpringSession緩存之實戰