SpringBoot使用Redis快取Shiro的Session以及遇到的坑
阿新 • • 發佈:2019-02-07
博主使用的是SpringBoot,如果是使用SpringMVC做框架則只要將註解轉化為xml就可以了。
實現思路
重寫shiro的`AbstractSessionDAO`,並將其注入到Shiro的SessionManager中,在SpringBoot的注入過程可以參考[這篇](https://blog.csdn.net/madonghyu/article/details/80111917),只要將快取快取redis就可以了。接下來主要是redis的使用
- 首先是SpringBoot整合Redis,首先在pom檔案加入依賴
<!-- redis整合SpringBoot用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 然後在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
- 最後在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。
- 下面主要說一下shiro的session快取出錯的解決方法,主要問題是session的序列化問題,如果使用上面的序列化方式,shiro的session序列化的時候會多出屬性,像是將
isValid
函式當成屬性序列化,這時使用阿里巴巴的fastjson也會序列化失敗(至少我是失敗的,可能是配置問題) - 解決session序列化問題方法也很簡單,第三步的
setValueSerializer
不配置就可以了。
如果想要redis資料庫的資料為json字串,那麼可以在其他用到快取的地方使用StringRedisTemplate
,或者再定義一個template。 - 如果想自定義序列化方法的話,那麼就只能自定義session的序列化方法了。理論上可以自定義JOSN序列化時的過濾掉屬性(我是沒成功過。。),我則是直接自定義一個
序列化方法
將session序列化成字串。
即自己實現一個將session序列化為字串和反序列化為SimpleSession
的函式。 - 總結,shiro的session序列化成json字串比較難,因此最好直接將其序列化成位元組碼。