본문 바로가기

Spring

Spring redis session 적용하기

728x90

지난 글에 이어서 스프링에 redis lettuce를 적용해봤다. 그래서 이제 서버단에서 redis로 데이터를 관리할 수 있게 되었지만, 사실 목적은 세션데이터를 redis로 클러스터링해서 관리하는것이다. 내 경우 톰캣이 1대여서 로드밸런싱은 필요없지만 서버를 재시작해도 세션이 남아있게 하기 위해 spring-session-data-redis를 활용해 세션또한 redis로 관리하기로 했다.

 

스프링 문서를 참고해 적용했다. 

https://docs.spring.io/spring-session/docs/current/reference/html5/#java-servlet-container-initialization

 

Spring Session

With the new major release version, the Spring Session team took the opportunity to make some non-passive changes. The focus of these changes is to improve and harmonize Spring Session’s APIs as well as remove the deprecated components. 11.1. Baseline Up

docs.spring.io

 

spring-session-data-redis 설정은 Java설정xml설정, 2가지 방법이 있다.

문서를 참고하면 두가지 방법 모두 나와있고 적용 방법도 매우 간단하다.

 

난 기존에 redis 적용을 xml로 했기때문에 xml설정을 적용했다.

 

pom.xml

<!-- redis -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.5.3</version>
</dependency>
<!-- end redis -->

기존의 dependency중 spring-session-data-redis만 추가했다.

 

root-context.xml

<!-- redis -->
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory" p:host-name="${REDIS_HOST}" p:port="${REDIS_PORT}" p:password="${REDIS_PASSWORD}" />

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connectionFactory-ref="redisConnectionFactory" />

<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connectionFactory-ref="redisConnectionFactory" />

<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />

<util:constant
static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>

먼저 namespace에 util을 체크해줘야한다.

추가된 항목중 먼저

<context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration" />

 

이 있는데 context:annotation-config의 경우 아직 스프링에서 session namespace를 제공하지 않기때문에 추가한 태그라고 한다.

 

RedisHttpSessionConfiguration bean을 생성하는 이유는, 스프링에서 기존에 사용하는 HttpSession을 대신해서 사용할 SpringSessionRepositoryFilter를 bean객체로 생성하기 위함인데 RedisHttpSessionConfiguration클래스에 내부적으로 SpringSessionRepositoryFilter의 빈을 생성한다고 주석된걸 볼 수 있었다.

 

 

사실 저부분만 추가해도 완료되지만

<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>을 추가하게 되었다.

이유는 redis에 세션이 쌓이게 되면 만료된 세션의 경우 destroy event가 진행되어야 하는데, 이 destroy event는 기본적으로 자동 설정이 되어있지만 보안의 redis 환경인 경우 동작하지 않는다고 한다.

참고 : https://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisindexedsessionrepository-sessiondestroyedevent

 

Spring Session

With the new major release version, the Spring Session team took the opportunity to make some non-passive changes. The focus of these changes is to improve and harmonize Spring Session’s APIs as well as remove the deprecated components. 11.1. Baseline Up

docs.spring.io

 

대부분은 당연히 redis의 보안을 적용하기 때문에 자동 설정을 비활성화 시키는  

org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP를 추가해줘야한다.

 

Java Config

Redis Template 관련 설정을 위해 자바설정을 하나 추가햇다.

package com.poozim.jobcall.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import com.poozim.jobcall.model.Member;
import com.poozim.jobcall.model.Work;

@Configuration
@Component
public class RedisConfig {

	private LettuceConnectionFactory redisConnectionFactory;
	
	@Autowired
	public RedisConfig(LettuceConnectionFactory redisConnectionFactory) {
		this.redisConnectionFactory = redisConnectionFactory;
	}
	
	@Bean
	public RedisTemplate<String, Work> workRedisTemplate() {
		RedisTemplate<String, Work> workRedisTemplate = new RedisTemplate<>();
		workRedisTemplate.setConnectionFactory(redisConnectionFactory);
		workRedisTemplate.setKeySerializer(new StringRedisSerializer());
		workRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Work>(Work.class));
		return workRedisTemplate;
	}
	
	@Bean
	public RedisTemplate<String, Member> memberRedisTemplate() {
		RedisTemplate<String, Member> memberRedisTemplate = new RedisTemplate<>();
		memberRedisTemplate.setConnectionFactory(redisConnectionFactory);
		memberRedisTemplate.setKeySerializer(new StringRedisSerializer());
		memberRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Member>(Member.class));
		return memberRedisTemplate;
	}
}

내 경우에는 Work와 Member라는 객체를 세션에 저장하기 때문에 두개로 나눴지만 사실 Map형태로 하나만 bean 설정을 해줘도 될거같다. 본인 입맛대로 하자.

 

 

** 설정 완료 후 서버를 시작할 때 SerializeException이 뜰 수 있다. 모델 객체를 세션에 저장한다면 해당 모델에 implements Serializable를 해주어야 한다.

 

 

결과

 

서버 시작 후 페이지를 열기 전에 work_1만 있었지만, 페이지 접속 후 session 관련 데이터가 추가된 걸 볼 수 있다.

 

또한 서버 재시작 후 다시 들어가도 로그인 유지가 그대로 되었다.

 

redis에 저장된 session데이터의 경우 만료시간이 지나면 자동으로 destroyed 되었다.

728x90