詳解springboot中redis的使用和分布式session共享問題
對于分布式使用Nginx+Tomcat實現(xiàn)負載均衡,最常用的均衡算法有IP_Hash、輪訓、根據(jù)權重、隨機等。不管對于哪一種負載均衡算法,由于Nginx對不同的請求分發(fā)到某一個Tomcat,Tomcat在運行的時候分別是不同的容器里,因此會出現(xiàn)session不同步或者丟失的問題。
實際上實現(xiàn)Session共享的方案很多,其中一種常用的就是使用Tomcat、Jetty等服務器提供的Session共享功能,將Session的內(nèi)容統(tǒng)一存儲在一個數(shù)據(jù)庫(如MySQL)或緩存(如Redis)中。
本文旨在解決分布式系統(tǒng)的session如何共享問題,大致思路:session放入redis。其他解決方案:持久化、放cache等都可以,但是自從有了redis,這完全可以變的簡簡單單。
本文大致分兩步:
1.springboot中如何使用redis。
2.redis如何解決session共享
pom依賴
<!--redis配置開始-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>${spring-data-redis.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!--redis配置結(jié)束-->
添加redis配置類
該配置類同樣可以配置緩存失效時間等。
package com.mos.quote.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
/**
* @author Administrator
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
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
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
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);
template.afterPropertiesSet();
return template;
}
@Bean
public CacheManager cacheManager(RedisTemplate<String,String> redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//設置緩存過期時間
rcm.setDefaultExpiration(600000);
return rcm;
}
}
配置redis服務
# Redis數(shù)據(jù)庫索引(默認為0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=192.168.1.118 # Redis服務器連接端口 spring.redis.port=6381 # Redis服務器連接密碼(默認為空) spring.redis.password= # 連接池最大連接數(shù)(使用負值表示沒有限制) spring.redis.pool.max-active=8 # 連接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.pool.max-wait=-1 # 連接池中的最大空閑連接 spring.redis.pool.max-idle=8 # 連接池中的最小空閑連接 spring.redis.pool.min-idle=0 # 連接超時時間(毫秒) spring.redis.timeout=0
單元測試
1、set值(字符串)
@Test
public void put(){
stringRedisTemplate.opsForValue().set("test001","test001");
Assert.assertEquals("test001", stringRedisTemplate.opsForValue().get("test001"));
}
往redis放一個key為test001、value為test001的值,然后查看redis

key=test001
2、set值(object)
@Test
public void testObj() throws Exception {
SysUser user=new SysUser();
user.setId("123456");
user.setName("張三");
ValueOperations<String, SysUser> operations=redisTemplate.opsForValue();
operations.set("user1", user);
operations.set("user2", user,5, TimeUnit.SECONDS);
Thread.sleep(6000);
Assert.assertFalse(redisTemplate.hasKey("user2"));
}
往redis分別放key為user1和user2的對象,user2設置5秒失效,線程等待6秒再完成,期望結(jié)果:redis中有user1,沒有user2,bingo!??!

ObjTest
解決session共享
使用spring-session-data-redis實現(xiàn)session共享,pom中引入該依賴(上文已添加),添加SessionConfig配置類。
對,沒看錯,只需要這個就夠了。最長有效時間根據(jù)自己情況隨意配置即可。
package com.mos.quote.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* @author Administrator
*/
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3000)
public class SessionConfig {
}
測試
寫一個簡單Controller,如下
@RequestMapping("testSessionTimeOut")
public String testSessionTimeOut(String id,HttpSession session,Model model){
Area area = areaService.getById(id);
System.out.println("sessionId-------->"+session.getId());
model.addAttribute("area",JSON.toJSONString(area));
session.setAttribute("area",JSON.toJSONString(area));
return "demo/test1";
}
這里可以看到sessionId:

sessionId
看redis中,可以看到失效時間,sessionId等

sessionId
共享session
另外找一個機器,照著這個配置再來一遍,自動啟用session共享,因為sessionId都存在了同一個redis中。奏是這么簡單。挽起袖子開始干吧。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
SpringBoot集成Aviator實現(xiàn)參數(shù)校驗的代碼工程
Aviator是一個高性能、輕量級的java語言實現(xiàn)的表達式求值引擎,主要用于各種表達式的動態(tài)求值,本文給大家詳細介紹了SpringBoot集成Aviator實現(xiàn)參數(shù)校驗的方法,并通過代碼示例講解的非常詳細,需要的朋友可以參考下2024-11-11
Spring data elasticsearch使用方法詳解
這篇文章主要介紹了Spring data elasticsearch使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-01-01
Java集合類的組織結(jié)構和繼承、實現(xiàn)關系詳解
這篇文章主要介紹了Java集合類的組織結(jié)構和繼承、實現(xiàn)關系,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11
SpringCloudAlibaba整合Feign實現(xiàn)遠程HTTP調(diào)用的簡單示例
這篇文章主要介紹了SpringCloudAlibaba 整合 Feign 實現(xiàn)遠程 HTTP 調(diào)用,文章中使用的是OpenFeign,是Spring社區(qū)開發(fā)的組件,需要的朋友可以參考下2021-09-09
Spring實戰(zhàn)之Qualifier注解用法示例
這篇文章主要介紹了Spring實戰(zhàn)之Qualifier注解用法,結(jié)合實例形式詳細分析了spring Qualifier注解相關配置、定義與使用方法,需要的朋友可以參考下2019-12-12

