詳解springboot中redis的使用和分布式session共享問題
對(duì)于分布式使用Nginx+Tomcat實(shí)現(xiàn)負(fù)載均衡,最常用的均衡算法有IP_Hash、輪訓(xùn)、根據(jù)權(quán)重、隨機(jī)等。不管對(duì)于哪一種負(fù)載均衡算法,由于Nginx對(duì)不同的請(qǐng)求分發(fā)到某一個(gè)Tomcat,Tomcat在運(yùn)行的時(shí)候分別是不同的容器里,因此會(huì)出現(xiàn)session不同步或者丟失的問題。
實(shí)際上實(shí)現(xiàn)Session共享的方案很多,其中一種常用的就是使用Tomcat、Jetty等服務(wù)器提供的Session共享功能,將Session的內(nèi)容統(tǒng)一存儲(chǔ)在一個(gè)數(shù)據(jù)庫(kù)(如MySQL)或緩存(如Redis)中。
本文旨在解決分布式系統(tǒng)的session如何共享問題,大致思路:session放入redis。其他解決方案:持久化、放cache等都可以,但是自從有了redis,這完全可以變的簡(jiǎn)簡(jiǎn)單單。
本文大致分兩步:
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配置類
該配置類同樣可以配置緩存失效時(shí)間等。
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);
//設(shè)置緩存過期時(shí)間
rcm.setDefaultExpiration(600000);
return rcm;
}
}
配置redis服務(wù)
# Redis數(shù)據(jù)庫(kù)索引(默認(rèn)為0) spring.redis.database=0 # Redis服務(wù)器地址 spring.redis.host=192.168.1.118 # Redis服務(wù)器連接端口 spring.redis.port=6381 # Redis服務(wù)器連接密碼(默認(rèn)為空) spring.redis.password= # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制) spring.redis.pool.max-active=8 # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制) spring.redis.pool.max-wait=-1 # 連接池中的最大空閑連接 spring.redis.pool.max-idle=8 # 連接池中的最小空閑連接 spring.redis.pool.min-idle=0 # 連接超時(shí)時(shí)間(毫秒) spring.redis.timeout=0
單元測(cè)試
1、set值(字符串)
@Test
public void put(){
stringRedisTemplate.opsForValue().set("test001","test001");
Assert.assertEquals("test001", stringRedisTemplate.opsForValue().get("test001"));
}
往redis放一個(gè)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的對(duì)象,user2設(shè)置5秒失效,線程等待6秒再完成,期望結(jié)果:redis中有user1,沒有user2,bingo!?。?/p>

ObjTest
解決session共享
使用spring-session-data-redis實(shí)現(xiàn)session共享,pom中引入該依賴(上文已添加),添加SessionConfig配置類。
對(duì),沒看錯(cuò),只需要這個(gè)就夠了。最長(zhǎng)有效時(shí)間根據(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 {
}
測(cè)試
寫一個(gè)簡(jiǎn)單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中,可以看到失效時(shí)間,sessionId等

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

