1. 程式人生 > >SpringBoot使用Redis快取Shiro的Session以及遇到的坑

SpringBoot使用Redis快取Shiro的Session以及遇到的坑

博主使用的是SpringBoot,如果是使用SpringMVC做框架則只要將註解轉化為xml就可以了。

實現思路

重寫shiro的`AbstractSessionDAO`,並將其注入到Shiro的SessionManager中,在SpringBoot的注入過程可以參考[這篇](https://blog.csdn.net/madonghyu/article/details/80111917),只要將快取快取redis就可以了。

接下來主要是redis的使用

  1. 首先是SpringBoot整合Redis,首先在pom檔案加入依賴
        <!-- redis整合SpringBoot用 -->
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
  1. 然後在SpringBoot中配置redis的具體配置
spring:
  redis:
    database: 0
    host: xxx
    port: 6379
    pool
: max-active: 5000 max-idle: 5000 max-wait: -1 min-idle: 0 password: xxx timeout: 2000
  1. 最後在springboot的啟動函式加上註解@EnableCaching就可以了。SpringBoot主要配置了RedisTemplate和StringRedisTemplate這兩個來操作redis,當然也可以自己配置。具體配置如下
/**
 * 單機版的Redis的配置實現
 */
@Configuration
public class RedisConfig extends
CachingConfigurerSupport { @Bean //這裡可以自定義cacheManager,像是自定義全域性的快取時間之類 public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) { return new RedisCacheManager(redisTemplate); } @Bean //自定義的cache生成器 public KeyGenerator keyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); }; } @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // 1.建立 redisTemplate 模版 RedisTemplate<String, Object> template = new RedisTemplate<>(); // 2.關聯 redisConnectionFactory template.setConnectionFactory(redisConnectionFactory); // 3.建立 序列化類 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); // 4.設定可見度 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 5.啟動預設的型別 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); // 6.序列化類,物件對映設定 jackson2JsonRedisSerializer.setObjectMapper(om); // 7.設定 value 的轉化格式和 key 的轉化格式 template.setValueSerializer(jackson2JsonRedisSerializer); template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public RedisTemplate<String, String> stringRedisTemplate(RedisConnectionFactory factory) { return new StringRedisTemplate(factory); } }

上面就是redis的配置,事實上你可以省略第三步的setValueSerializer,通過檢視template.afterPropertiesSet();這個函式的原始碼,可以發現當沒有設定ValueSerializer的時候,會預設使用JdkSerializationRedisSerializer,這個序列化模式會將value序列化成位元組碼,這樣快取shiro的session就沒有什麼問題,當是redis資料庫的資料將是位元組碼,不方便觀察。如果只是想實現快取,不想將其序列化化為json字串,你完全可以只使用SpringBoot自動配置的template。

  1. 下面主要說一下shiro的session快取出錯的解決方法,主要問題是session的序列化問題,如果使用上面的序列化方式,shiro的session序列化的時候會多出屬性,像是將isValid函式當成屬性序列化,這時使用阿里巴巴的fastjson也會序列化失敗(至少我是失敗的,可能是配置問題)
  2. 解決session序列化問題方法也很簡單,第三步的setValueSerializer不配置就可以了。
    如果想要redis資料庫的資料為json字串,那麼可以在其他用到快取的地方使用StringRedisTemplate,或者再定義一個template。
  3. 如果想自定義序列化方法的話,那麼就只能自定義session的序列化方法了。理論上可以自定義JOSN序列化時的過濾掉屬性(我是沒成功過。。),我則是直接自定義一個序列化方法將session序列化成字串。
    即自己實現一個將session序列化為字串和反序列化為SimpleSession的函式。
  4. 總結,shiro的session序列化成json字串比較難,因此最好直接將其序列化成位元組碼。