스프링 세션은 사용자의 세션 정보를 관리하기 위하여 API와 구현체를 제공합니다.

Spring Session provides an API and implementations for managing a user’s session information.

소개
Introduction

스프링 세션은 사용자의 세션정보를 관리하기 위해 API와 구현체들을 제공하지만, 또한 다음 것들과의 투명한 통합을 제공합니다 :

Spring Session provides an API and implementations for managing a user’s session information. It also provides transparent integration with:

  • HttpSession - (톰캣같은) 어플리케이션 콘테이너에서 HttpSession을 바꾸게 합니다. 중립적인 방법으로. 추가적인 특징이 포함됩니다. (원문 : neutral way.Additional features include):

    HttpSession - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way.Additional features include:

    • 클러스터 세션들 - 스프링 세션은 클러스터된 세션들에 대한 지원을, 특정 어플리케이션 콘테이너 솔루션에 묶이지 않으면서 간편하게(의역:trivial) 만듭니다.

      Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.

    • 여러개의 브라우저 세션들 - 스프링 세션은 여러개의 유저 세션을 관리하는 것 을 단일 브라우저 인스턴스 내에서 지원합니다. (예.구글과 비슷한 여러개의 인증된 계정)

      Multiple Browser Sessions - Spring Session supports managing multiple users' sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).

    • RESTful APIs - 스프링세션은 RESTful APIs와 함께 헤더에 세션 id들을 제공하는 것을 허용합니다.

      RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs

  • WebSocket - WebSocket을 받을 때, HttpSession 를 alive하게 해줍니다.

    WebSocket - provides the ability to keep the HttpSession alive when receiving WebSocket messages

샘플과 가이드 (여기서 시작 )
Samples and Guides (Start Here)

만약 당신이 스프링세션에서 시작하기를 원한다면, 우리의 예제 어플리케이션들로 시작해보세요

If you are looking to get started with Spring Session, the best place to start is our Sample Applications.

표 1.예제 어플리케이션들 Table 1. Sample Applications
Source Description Guide

HttpSession

스프링세션을 사용하여 HttpSession을 레디스 스토어로 어떻게 변환하는지 보여줍니다.

Demonstrates how to use Spring Session to replace the HttpSession with a Redis store.

HttpSession XML

XML기반의 설정을 사용하고 스프링세션을 사용하여 HttpSession을 어떻게 레디스 스토어로 변환하는지 보여줍니다.

Demonstrates how to use Spring Session to replace the HttpSession with a Redis store using XML based configuration.

HttpSession XML Guide

Spring Boot

스프링세션을 어떻게 스프링부트에서 사용하는지 보여줍니다.

Demonstrates how to use Spring Session with Spring Boot.

Spring Boot Guide

Spring Security

존재하는 스프링시큐리티 어플리케션과 스프링세션을 어떻게 같이 사용하는지 보여줍니다.

Demonstrates how to use Spring Session with an existing Spring Security application.

Spring Security Guide

REST

헤더와 함께 인증을 지원하는 REST 어플리케이션에서 어떻게 스프링 세션을 사용하는지 보여줍니다.

Demonstrates how to use Spring Session in a REST application to support authenticating with a header.

REST Guide

Multiple Users

스프링세션을 사용하여서 어떻게 여러개의 동시 브라우저 세션(구글 계정같은) 들을 관리하는지 보여줍니다.

Demonstrates how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts).

Manage Multiple Users Guide

WebSocket

스프링세션과 웹소켓을 어떻게 사용하는지 보여줍니다 .

Demonstrates how to use Spring Session with WebSockets.

WebSocket Guide

Hazelcast

스프링 세션과 Hazelcast를 어떻게 사용하는지 보여줍니다.

Demonstrates how to use Spring Session with Hazelcast.

TBD

HttpSession 통합
HttpSession Integration

스프링 세션은 HttpSession과의 투명한 통합을 제공합니다.이것은 개발자가 HttpSession 구현체를 스프링세션 구현체로 전환할 수 있다는 것을 의미합니다. (의역 )

왜 스프링세션&HttpSession인가요?
Why Spring Session & HttpSession?

우리는 이미 스프링세션이 HttpSession과의 투명한 통합을 제공한다고 얘기했는데, 이것으로 우리가 무슨 이익이 있을까요?

We have already mentioned that Spring Session provides transparent integration with HttpSession, but what benefits do we get out of this?

  • Clustered Sessions - 스프링 세션은 clustered sessions에 대한 지원을 쉽게(trivial) 해줍니다.

    Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.

  • Multiple Browser Sessions - 스프링 세션은 단일 브라우저 인스턴스에서 여러 유저의 세션관리(managing multiple users' sessions)를 가능하게 해줍니다. (예.구글과 비슷한 여러개의 인증된 계정)

    Multiple Browser Sessions - Spring Session supports managing multiple users' sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).

  • RESTful APIs - 스프링세션은 RESTful APIs와 함께 헤더에 세션 id들을 제공하는 것을 허용합니다.

    RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs

Redis와 HttpSession
HttpSession with Redis

HttpSession을 사용하기 이전에(의역 조금 추가), 서블릿필터를 추가해줌으로써 HttpSession과 스프링세션을 활성화시킬 수 있습니다.

Using Spring Session with HttpSession is enabled by adding a Servlet Filter before anything that uses the HttpSession.

레디스 자바 기반 설정

Redis Java Based Configuration

이 섹션은 자바 설정기반을 사용하여, HttpSession뒤에서(back) 어떻게 레디스를 사용하는지 설명합니다.

This section describes how to use Redis to back HttpSession using Java based configuration.

The HttpSession Sample은 스프링 세션과 HttpSession을 어떻게 통합시키는 지 보여주는 예제(XML설정)를 제공합니다.
You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession Guide when integrating with your own application.
스프링 자바 설정
Spring Java Configuration

요청 의존성을 추가한 이후에, 스프링 설정을 생성할 수 있습니다. 스프링설정은 서블릿필터를 만들어내는 책임이 있으며, 이 필터는 HttpSession구현체를 스프링세션의 구현체로 바꿔줍니다.

After adding the required dependencies, we can create our Spring configuration. The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession implementation with an implementation backed by Spring Session. Add the following Spring Configuration:

@EnableEmbeddedRedis (1)
@EnableRedisHttpSession (2)
public class Config {

        @Bean
        public JedisConnectionFactory connectionFactory(@RedisServerPort int port) {
                JedisConnectionFactory connection = new JedisConnectionFactory(); (3)
                connection.setPort(port);
                return connection;
        }
}
1
우리는 내장 레디스 서버를 임포트하여서 우리의 어플리 케이션 바깥의 레디스를 시작할 필요가 없습니다. 프로덕션 어플리케이션에서는 우리는 커넥션을 외부 레디스 인스턴스로 가리킬 것이기 때문에 이것은 필요가 없습니다.
We import an embedded Redis Server so that there is no need to start up Redis external of our application. In a production application this is not necessary since we would point our connection to an external Redis instance.
2
The @EnableRedisHttpSession 어노테이션은 필터를 구현하는 springSessionRepositoryFilter라는 이름을 가진 스프링빈을 생성시킵니다. 그 필터는 HttpSession 구현체가 스프링 세션에 의해 지원되게 하는데 (be backed by) 책임이 있습니다. 이 인스턴스에서는 스프링 세션은 레디스에 의해 지원됩니다(backed by)
The @EnableRedisHttpSession annotation creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis.
3
우리는 RedisConnectionFactory을 생성하여 스프링 세션을 레디스 서버로 연결시킬 것입니다. PropertyPlaceholderConfigurer를 사용하여서 포트 위치를 외부화 시킬 것입니다. 더 많은 스프링 데이터 레디스 정보를 위해서 reference documentation를 참조하세요
We create a RedisConnectionFactory that connects Spring Session to the Redis Server. We use a PropertyPlaceholderConfigurer to externalize the port location. For more information on configuring Spring Data Redis, refer to the reference documentation.
자바 서블릿 컨테이너 초기화
Java Servlet Container Initialization

우리의 Spring Configuration 은 필터를 구현하는 springSessionRepositoryFilter라 불리는 스프링 빈에 의해 생성됩니다.

The springSessionRepositoryFilter bean is responsible for replacing the HttpSession with a custom implementation that is backed by Spring Session.

우리의 Filter 가 이러한 마법같은 일을 하게 하기 위해, 스프링은 우리의 Config클래스를 불러올 필요가 있습니다. 마지막으로 우리는 모든 요청에서 서블릿 컨테이너(예를 들면 톰캣)가 우리의 springSessionRepositoryFilter를 사용하는 것을 보장해야 합니다. 다행스럽게도 스프링 세션은 AbstractHttpSessionApplicationInitializer라는 유틸리티 클래스를 제공하며, 위의 두 단계는 무척 쉽습니다. 당신은 아래에서 예제를 찾을 수 있습니다.

In order for our Filter to do its magic, Spring needs to load our Config class. Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our springSessionRepositoryFilter for every request. Fortunately, Spring Session provides a utility class named AbstractHttpSessionApplicationInitializer both of these steps extremely easy. You can find an example below:

src/main/java/sample/Initializer.java
public class Initializer
                extends AbstractHttpSessionApplicationInitializer { (1)

        public Initializer() {
                super(Config.class); (2)
        }
}
우리의 초기화 클래스의 이름은 중요치 않습니다. 중요한 것은 우리가 AbstractHttpSessionApplicationInitializer를 상속한다는 것입니다 .
The name of our class (Initializer) does not matter. What is important is that we extend AbstractHttpSessionApplicationInitializer.
1
첫번째 단계는 AbstractHttpSessionApplicationInitializer를 상속하는 것이고, 이것은 springSessionRepositoryFilter이라 이름 붙여진 빈이 모든 요청을 위해서 서블릿 컨테이너에 등록되게 해줍니다.
The first step is to extend AbstractHttpSessionApplicationInitializer. This ensures that the Spring Bean by the name springSessionRepositoryFilter is registered with our Servlet Container for every request.
2
AbstractHttpSessionApplicationInitializer 는 또한 쉽게 Config를 불러오는 것을 보장하는 메커니즘을 제공합니다.
AbstractHttpSessionApplicationInitializer also provides a mechanism to easily ensure Spring loads our Config.

레디스 XML 기반 설정
Redis XML Based Configuration

이 섹션은 어떻게 레디스를 HttpSession뒤에서 사용할 수 있는지 설명합니다.

This section describes how to use Redis to back HttpSession using XML based configuration.

HttpSession XML Sample은 어떻게 스프링세션과 HttpSession를 XML설정을 사용하여 통합시키는지 보여주는 예제를 제공합니다. 당신은 통합을 위해 다음과 같은 기본적인 단계를 읽을 수 있으며, 당신 자신의 어플리케이션을 통합할때 세부적인 HTML 세션 XML 가이드를 봐야할 것입니다.
HttpSession XML Sample provides a working sample on how to integrate Spring Session and HttpSession using XML configuration. You can read the basic steps for integration below, but you are encouraged to follow along with the detailed HttpSession XML Guide when integrating with your own application.
스프링 XML 설정
Spring XML Configuration

필요한 의존성을 추가한 이후에 우리의 스프링 설정을 생성할 수 있습니다. 이 스프링 설정은 HttpSession 구현체가 스프링세션에 관리되는(backed by) 구현체로 대체하게 하는 서블릿 필터를 생성하는 책임이 있습니다. 다음의 설정을 추가해주세요. :

After adding the required dependencies, we can create our Spring configuration. The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession implementation with an implementation backed by Spring Session. Add the following Spring Configuration:

src/main/webapp/WEB-INF/spring/session.xml
<bean class="org.springframework.session.redis.embedded.EmbeddedRedisConfiguration"/> (1)

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

(3)
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
    p:port="${spring.redis.port}"/>
1
우리는 내장된 레디스 서버를 생성하여 어플리케이션 외부의 레디스를 시작할 필요가 없게됩니다. 프로덕션 어플리케이션에서는 우리는 이 코넥션을 외부 레디스 인스턴스로 연결시킬 것이므로 이것은 필요치 않습니다.
We create an embedded Redis Server so that there is no need to start up Redis external of our application. In a production application this is not necessary since we would point our connection to an external Redis instance.
2
우리는 <context:annotation-config/>RedisHttpSessionConfiguration의 조합을 사용할 것입니다. 왜냐하면 스프링 세션은 아직 XML 네임스페이스 설정을 지원하지 않기 때문입니다. ( gh-104을 보세요) 이것은 필터를 구현하는 springSessionRepositoryFilter이라는 이름의 스프링 빈을 생성할 것입니다. 저 필터는 HttpSession구현체를 스프링세션에 지원(backed by)되는 구현체로 바꾸게 해줄 것입니다. 이 인스턴스에서 스프링세션은 레디스에 의해 지원(backed by)됩니다.
We use the combination of <context:annotation-config/> and RedisHttpSessionConfiguration because Spring Session does not yet provide XML Namespace support (see gh-104). This creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis.
3
우리는 RedisConnectionFactory 을 생성하여서 스프링세션을 레디스 서버에 연결시킬 것입니다. PropertyPlaceholderConfigurer를 사용하여 포트위치를 외부화시킬 것입니다. 스프링 데이터 레디스 설정에 관한 더 많은 정보는 reference documentation를 참고하세요
We create a RedisConnectionFactory that connects Spring Session to the Redis Server. We use a PropertyPlaceholderConfigurer to externalize the port location. For more information on configuring Spring Data Redis, refer to the reference documentation.
XML 서블릿 컨테이너 초기화
XML Servlet Container Initialization

우리의 스프링 설정은 Filter를 구현하는 springSessionRepositoryFilter라는 이름의 스프링빈을 생성할 것입니다. springSessionRepositoryFilter빈은 HttpSession을 스프링세션에 의해 지원(backed by)되는 커스텀 구현체로 바꿔주는 책임이 있습니다.

Our Spring Configuration created a Spring Bean named springSessionRepositoryFilter that implements Filter. The springSessionRepositoryFilter bean is responsible for replacing the HttpSession with a custom implementation that is backed by Spring Session.

우리의 필터가 이런 마법과 같은 일을 하게 하기 위해, 우리는 스프링에게 session.xml설정을 불러오게 해줘야 합니다.

We do this with the following configuration:

src/main/webapp/WEB-INF/web.xml
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/spring/*.xml
    </param-value>
</context-param>
<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

ContextLoaderListener는 contextConfigLocation을 읽고서, session.xml설정을 고릅니다.

The ContextLoaderListener reads the contextConfigLocation and picks up our session.xml configuration.

Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our springSessionRepositoryFilter for every request. The following snippet performs this last step for us:

src/main/webapp/WEB-INF/web.xml
<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

DelegatingFilterProxyspringSessionRepositoryFilter 라는 이름으로 빈을 찾아서, Filter로 형변환 할 것입니다. DelegatingFilterProxy가 발동하는(invoked) 모든 요청들은 springSessionRepositoryFilter가 발동(invoked) 될 것입니다 .

The DelegatingFilterProxy will look up a Bean by the name of springSessionRepositoryFilter and cast it to a Filter. For every request that DelegatingFilterProxy is invoked, the springSessionRepositoryFilter will be invoked.

어떻게 HTTP세션 통합이 동작하는가?
How HttpSession Integration Works

다행스럽게도 HttpSessionHttpServletRequest( HttpSession를 얻기 위한 API) 은 둘다 인터페이스들입니다. 이것은 우리가 이러한 API들을 위한 우리 자신의 API을 제공할 수 있다는 것을 의미합니다.

Fortunately both HttpSession and HttpServletRequest (the API for obtaining an HttpSession) are both interfaces. This means that we can provide our own implementations for each of these APIs.

이 섹션에서는 어떻게 HttpSession에서의 스프링 세션이 투명한 통합을 제공하는지 설명합니다. 사용자가 무엇이 밑에서 일어나는지 이해할 수 있게 하는 것이 의도이며, 이러한 기능은 이미 통합되었으므로, 당신은 이러한 로직을 스스로 구현할 필요가 없습니다.
This section describes how Spring Session provides transparent integration with HttpSession. The intent is so that user’s can understand what is happening under the covers. This functionality is already integrated and you do NOT need to implement this logic yourself.

먼저 커스텀 HttpSession구현체를 반환하는 커스텀 HttpServletRequest를 생성합니다. 다음과 같을 것입니다 :

First we create a custom HttpServletRequest that returns a custom implementation of HttpSession. It looks something like the following:

public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {

        public SessionRepositoryRequestWrapper(HttpServletRequest original) {
                super(original);
        }

        public HttpSession getSession() {
                return getSession(true);
        }

        public HttpSession getSession(boolean createNew) {
                // create an HttpSession implementation from Spring Session
        }

        // ... other methods delegate to the original HttpServletRequest ...
}

HttpSession를 반환하는 어떤 메소드든지 간에 오버라이딩되었습니다. HttpServletRequestWrapper 에 의해서 모든 다른 메소드들이 구현되고, 단순히 HttpServletRequest구현체로 위임됩니다.

Any method that returns an HttpSession is overridden. All other methods are implemented by HttpServletRequestWrapper and simply delegate to the original HttpServletRequest implementation.

우리는 HttpServletRequest 구현체를 SessionRepositoryFilter라 불리는 서블릿 필터를 이용하여서 전환할 것입니다 수도코드는 다음과 같습니다 :

We replace the HttpServletRequest implementation using a servlet Filter called SessionRepositoryFilter. The pseudocode can be found below:

public class SessionRepositoryFilter implements Filter {

        public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                SessionRepositoryRequestWrapper customRequest =
                        new SessionRepositoryRequestWrapper(httpRequest);

                chain.doFilter(customRequest, response, chain);
        }

        // ...
}

커스텀HttpServletRequest구현체를 FilterChain에 전달(pass)함으로써 , 우리는 Filter이후로 발동(invoked)되는 어떤 것이든, 커스텀 HttpSession구현체를 사용하는 것을 보장할 수가 있습니다. 이것은 스프링 세션의 SessionRepositoryFilterHttpSession와 상호작용하는 것들 이전에 놓여져야하는것이 왜 중요한지 강조합니다.

By passing in a custom HttpServletRequest implementation into the FilterChain we ensure that anything invoked after our Filter uses the custom HttpSession implementation. This highlights why it is important that Spring Session’s SessionRepositoryFilter must be placed before anything that interacts with the HttpSession.

단일 브라우저에서의 여러개의(multiple) 세션들
Multiple HttpSessions in Single Browser

스프링 세션은 단일 브라우저 인스턴스에서 여러개의 세션을 지원할 수 있습니다. 이것은 같은 브라우저 인스턴스에서 (구글계정처럼) 여러개의 사용자를 인증하는 것을 지원합니다.

Spring Session has the ability to support multiple sessions in a single browser instance. This provides the ability to support authenticating with multiple users in the same browser instance (i.e. Google Accounts).

Manage Multiple Users Guide 는 같은 브라우저 인스턴스에서 여러 사용자들을 관리하는 잘 동작하는 예제를 보여줍니다. 당신은 다음의 통합을 위해 기본적인 단계를 따라해볼 수 있지만, 당신 자신의 어플리케이션에서 통합할 때는 세부적인 멀티유저가이드를 따라야할 것입니다.
The Manage Multiple Users Guide provides a complete working example of managing multiple users in the same browser instance. You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed Manage Multiple Users Guide when integrating with your own application.

그럼 어떻게 스프링세션이 멀티 세션들을 파악(keep track of) 하는지 알아보도록 하겠습니다.

Let’s take a look at how Spring Session keeps track of multiple sessions.

Managing a Single Session

스프링 세션은 SESSION이라는 이름의 쿠키에 값을 더함으로써 HttpSession을 파악(keep track of)하고 있습니다. 예를 들자면, SESSION 쿠키는 다음의 과 같은 값을 가질 것입니다. :

Spring Session keeps track of the HttpSession by adding a value to a cookie named SESSION. For example, the SESSION cookie might have a value of:

7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

Adding a Session

우리는 특별한 파라미터를 포함하는 URL을 요청함으로써 , 다른 세션을 추가할 수가 있습니다. 기본적으로 파라미터이름은 _s입니다. 예를들어서 다음의 URL은 새로운 세션을 생성할 것입니다 :

We can add another session by requesting a URL that contains a special parameter in it. By default the parameter name is _s. For example, the following URL would create a new session:

저 파라미터 값은 실제 세션 아이디를 가리키지는 않습니다. 우리는 세션 fixation 공격들을 피하기 위해 세션아이디가 클라이언트에 의해 결정되는 것을 원하지 않으므로 이것은 중요하다고 할 수 있습니다. 추가적으로, 우리는 세션아이디가 쿼리 파라미터같은 걸로 유출되지 않기를 원합니다. 민감한 정보는 헤더나 리퀘스트 바디로 전송되어야 한다는 것을 기억합시다.
The parameter value does not indicate the actual session id. This is important because we never want to allow the session id to be determined by a client to avoid session fixation attacks. Additionally, we do not want the session id to be leaked since it is sent as a query parameter. Remember sensitive information should only be transmitted as a header or in the body of the request.

우리자신이 URL을 만들기보다, 우리는 이러한 것들을 하는 HttpSessionManager를 이용할 수가 있습니다. 우리는 HttpServletRequest로부터 HttpSessionManager를 얻을 수가 있을 것입니다 :

Rather than creating the URL ourselves, we can utilize the HttpSessionManager to do this for us. We can obtain the HttpSessionManager from the HttpServletRequest using the following:

src/main/java/sample/UserAccountsFilter.java
HttpSessionManager sessionManager =
        (HttpSessionManager) httpRequest.getAttribute(HttpSessionManager.class.getName());

우리는 이제 이것을 사용하여, 다른 세션을 추가할 URL을 생성할 수가 있을 것입니다.

We can now use it to create a URL to add another session.

src/main/java/sample/UserAccountsFilter.java
String addAlias = unauthenticatedAlias == null ? (1)
        sessionManager.getNewSessionAlias(httpRequest) : (2)
        unauthenticatedAlias; (3)
String addAccountUrl = sessionManager.encodeURL(contextPath, addAlias); (4)
1
우리는 unauthenticatedAlias라 불리는 존재하는(existing)변수 를 가지고 있습니다. 이 값은 인증되지 않고 존재하는 세션을 가리키는 별명(alias) 입니다. 세션값이 없을 경우에는 이 값은 null이 됩니다. 이것은 우리가 인증되지 않고 존재하는 세션을 가지고 있다면, 새로운 세션을 생성하는 대신에 인증되지 않은 세션을 사용하려 한다는 것을 보장해줍니다.
We have an existing variable named unauthenticatedAlias. The value is an alias that points to an existing unauthenticated session. If no such session exists, the value is null. This ensures if we have an existing unauthenticated session that we use it instead of creating a new session.
2
만약 우리의 모든 세션이 이미 사용자와 연관되어져있다면, 우리는 새로운 세션 별명(alias)을 만들 것입니다.
If all of our sessions are already associated to a user, we create a new session alias.
3
만약 사용자와 연관되어져있지 않은 존재하는 세션이 있다면, 우리는 그것을 사용할 것입니다.
If there is an existing session that is not associated to a user, we use its session alias.
4
마침내, 우리는 추가된 계정URL을 생성할 것입니다. 이 URL은 세션 별명을 포함하며, 이 별명은 인증되지 않은 존재하는 세션을 가리키거나, 사용되지 않은 별칭을 가리킵니다.
Finally, we create the add account URL. The URL contains a session alias that either points to an existing unauthenticated session or is an alias that is unused thus signaling to create a new session associated to that alias.

그럼, 우리의 세션 쿠키는 다음과 같을 것입니다 :

Now our SESSION cookie looks something like this:

0 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 1 1d526d4a-c462-45a4-93d9-84a39b6d44ad

Such that:

  • id가 다음과 같은 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 세션일 것입니다.

    There is a session with the id 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

    • 이 세션에 대한 별칭은 0입니다. 예를 들어서 만약 URL이 http://localhost:8080/?_s=0이면 이 별칭이 사용될 것입니다.

      The alias for this session is 0. For example, if the URL is http://localhost:8080/?_s=0 this alias would be used.

    • 이것은 기본 세션입니다. 이것은 어떠한 세션별칭이 명시되지 않으면 이 세션이 사용될 것이란 것을 의미합니다. 예를 들어 만약 URL이 http://localhost:8080/이면 이 세션이 사용될 것입니다.

      This is the default session. This means that if no session alias is specified, then this session is used. For example, if the URL is http://localhost:8080/ this session would be used.

  • id 1d526d4a-c462-45a4-93d9-84a39b6d44ad를 가진 세션이 있습니다.

    There is a session with the id 1d526d4a-c462-45a4-93d9-84a39b6d44ad

    • 이 세션에 대한 별명은 1입니다. 만약 세션별명이 1 이라면, 이 세션은 사용되는 것입니다. 예를 들어서 http://localhost:8080/?_s=1가 URL 이면 이 별칭이 사용되는 것입니다.

      The alias for this session is 1. If the session alias is 1, then this session is used. For example, if the URL is http://localhost:8080/?_s=1 this alias would be used.

인코드된 URL에서의 자동적 세션별명 포함
Automatic Session Alias Inclusion with encodeURL

URL에서 세션별명을 명시해주는 것의 좋은 점은 다른 액티브세션들과 함께 여러개의 탭을 가질 수가 있다는 것입니다. 나쁜 것은 우리 어플리케이션의 모든 URL에 세션 별명을 포함시킬 필요가 있다는 것입니다. 다행스럽게도 스프링 세션은 HttpServletResponse#encodeURL(java.lang.String)를 통해 전달되는 모든 URL에서 자동적으로 세션별명을 포함시킵니다.

The nice thing about specifying the session alias in the URL is that we can have multiple tabs open with different active sessions. The bad thing is that we need to include the session alias in every URL of our application. Fortunately, Spring Session will automatically include the session alias in any URL that passes through HttpServletResponse#encodeURL(java.lang.String)

이것은 만약 당신이 표준 태그라이브러리들을 사용한다면, 세션 별명이 자동적으로 URL에 포함됨을 의미합니다. 예를 들어서 당신이 만약 1의 별명을 가진 세션을 사용하고 있다면 다음과 같을 것입니다 :

This means that if you are using standard tag libraries the session alias is automatically included in the URL. For example, if we are currently using the session with the alias of 1, then the following:

src/main/webapp/index.jsp
  -->
<c:url value="/link.jsp" var="linkUrl"/>
<a id="navLink" href="${linkUrl}">Link</a>

링크 결과는 :

will output a link of:

<a id="navLink" href="/link.jsp?_s=1">Link</a>

HTTP세션의 RESTful API들
HttpSession & RESTful APIs

스프링 세션은 헤더에 제공되는 세션을 허용케 함으로써, RESTFUL API와 함께 동작할 수 있습니다.

Spring Session can work with RESTful APIs by allowing the session to be provided in a header.

REST Sample은 스프링 세션이 REST 어플리케이션에서 어떻게 헤더인증을 지원하는 지 나타내는 예제를 제공합니다. 당신은 기본 통합 단계를 따라갈 수 있지만, 세부적인 어쩌고 저쩌고 (-_-반복된 내용이다 )
The REST Sample provides a working sample on how to use Spring Session in a REST application to support authenticating with a header. You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed REST Guide when integrating with your own application.

스프링 설정
Spring Configuration

요청된 의존성을 추가한 이후에, 우리는 스프링 설정을 생성할 것입니다. 스프링 설정은 HttpSession 구현체를 스프링세션에 의해 지원되는(backed by) 구현체로 바꾸는 데 책임이 있는 서블릿 필터를 생성할 것입니다. 다음이 스프링 설정 :

After adding the required dependencies, we can create our Spring configuration. The Spring configuration is responsible for creating a Servlet Filter that replaces the HttpSession implementation with an implementation backed by Spring Session. Add the following Spring Configuration:

@Configuration
@EnableEmbeddedRedis (1)
@EnableRedisHttpSession (2)
public class HttpSessionConfig {

        @Bean
        public JedisConnectionFactory connectionFactory(@RedisServerPort int port) {
                JedisConnectionFactory factory = new JedisConnectionFactory();  (3)
                factory.setPort(port);
                return factory;
        }

        @Bean
        public HttpSessionStrategy httpSessionStrategy() {
                return new HeaderHttpSessionStrategy(); (4)
        }
}
1
우리는 내장된 레디스 서버를 임포트하여서 어플리케이션 바깥의 외부 레디스를 실행시킬 필요가 없습니다. 프로덕션에서는 우리는 외부 레디스 인스턴스접속을 가리킬 것이기 이것은 필요하지 않습니다.
We import an embedded Redis Server so that there is no need to start up Redis external of our application. In a production application this is not necessary since we would point our connection to an external Redis instance.
2
The @EnableRedisHttpSession 어노테이션은 필터를 구현하는 springSessionRepositoryFilter라는 이름을 가진 스프링빈을 생성시킵니다. 그 필터는 HttpSession 구현체가 스프링 세션에 의해 지원되게 하는데 (be backed by) 책임이 있습니다. 이 인스턴스에서는 스프링 세션은 레디스에 의해 지원됩니다(backed by)
The @EnableRedisHttpSession annotation creates a Spring Bean with the name of springSessionRepositoryFilter that implements Filter. The filter is what is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis.
3
우리는 RedisConnectionFactory을 생성하여 스프링 세션을 레디스 서버로 연결시킬 것입니다. PropertyPlaceholderConfigurer를 사용하여서 포트 위치를 외부화 시킬 것입니다. 더 많은 스프링 데이터 레디스 정보를 위해서 reference documentation를 참조하세요
We create a RedisConnectionFactory that connects Spring Session to the Redis Server. We use a PropertyPlaceholderConfigurer to externalize the port location. For more information on configuring Spring Data Redis, refer to the reference documentation.
4
우리는 스프링 세션의 HTTPSession통합을 커스터마이징해서, 현재 세션정보를 쿠키 대신 전달하기위한 HTTP헤더를 사용할 것입니다.
We customize Spring Session’s HttpSession integration to use HTTP headers to convey the current session information instead of cookies.

서블릿 콘테이너 초기화
Servlet Container Initialization

우리의 스프링 설정은 Filter를 구현하는 springSessionRepositoryFilter라는 이름의 스프링빈을 생성할 것입니다. springSessionRepositoryFilter빈은 HttpSession을 스프링세션에 의해 지원(backed by)되는 커스텀 구현체로 바꿔주는 책임이 있습니다.

Our Spring Configuration created a Spring Bean named springSessionRepositoryFilter that implements Filter. The springSessionRepositoryFilter bean is responsible for replacing the HttpSession with a custom implementation that is backed by Spring Session.

우리의 필터가 이러한 마법같은 일을 하게 하기 위해, 스프링은 Config클래스를 불러들일 필요가 있습니다. 우리의 스프링 MvcInitializer에서 다음과 같은 설정을 제공합니다 :

In order for our Filter to do its magic, Spring needs to load our Config class. We provide the configuration in our Spring MvcInitializer as shown below:

src/main/java/sample/mvc/MvcInitializer.java
@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class[] {SecurityConfig.class, HttpSessionConfig.class};
}

마지막으로 우리의 서블릿 컨테이너가 (예를 들면 톰캣) 모든 요청에서 우리의 springSessionRepositoryFilter를 사용하는 것을 보장할 필요가 있습니다. 다행스럽게도 스프링 세션은 AbstractHttpSessionApplicationInitializer라는 유틸리티 클래스를 제공하여 이러한 일을 무척 쉽게 해줍니다. 다음과 같이, 단순히 이 클래스를 기본 생성자와 함께 상속해주면 됩니다.

Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our springSessionRepositoryFilter for every request. Fortunately, Spring Session provides a utility class named AbstractHttpSessionApplicationInitializer that makes this extremely easy. Simply extend the class with the default constructor as shown below:

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
우리의 클래스의 이름 (Initializer)은 중요하지 않고, AbstractHttpSessionApplicationInitializer를 상속한 것이 중요합니다.
The name of our class (Initializer) does not matter. What is important is that we extend AbstractHttpSessionApplicationInitializer.

웹소켓 통합
WebSocket Integration

스프링 세션은 스프링 웹 소켓지원에의 투명한 통합을 제공합니다.

Spring Session provides transparent integration with Spring’s WebSocket support.

스프링-세션의 웹소켓은 오직 스프링의 웹소켓 지원과만 동작합니다. 명시적으로 JSR-356을 직접적으로 사용하는 것은 동작하지 않습니다. 이것은 JSR-356 이 웹소켓 메시지와 상호작용하는 메커니즘을 가지고 않기 때문입니다.
Spring Session’s WebSocket support only works with Spring’s WebSocket support. Specifically it does not work with using JSR-356 directly. This is due to the fact that JSR-356 does not have a mechanism for intercepting incoming WebSocket messages.

왜 스프링 세션&웹소켓인가요?
Why Spring Session & WebSockets?

그래서 왜 우리가 웹소켓을 사용할 때 스프링 세션을 필요로 하는가요?

So why do we need Spring Session when using WebSockets?

HTTP 요청을 통해 많은 일을 하는, 이메일 어플리케이션을 가정해봅시다. 그러나 또한 웹소켓 API를 통해 채팅 어플리케이션이 내장되어있습니다. 만약 사용자가 누군가와 채팅을 한다면, 우리는 HttpSession을 타입아웃하지 않을 것입니다. 이것은 아주 나쁜 사용자 경험이기 때문입니다. 그러나, JSR-356가 정확히 이것(타임아웃)을 합니다.

Consider an email application that does much of its work through HTTP requests. However, there is also a chat application embedded within it that works over WebSocket APIs. If a user is actively chatting with someone, we should not timeout the HttpSession since this would be pretty poor user experience. However, this is exactly what JSR-356 does.

JSR-356에 관한 다른 이슈는 HttpSession이 HttpSession과 함께 생성된 웹소켓을 타움아웃시키고, 인증된 사용자가 강제적으로 닫히는(closed)되는 것입니다. 이것은 우리가 어플리케이션에서 채팅을 하는데, HttpSession을 사용하지 않는다면, 우리는 대화에서 접속이 끊긴다는 것을 의미합니다.

Another issue is that according to JSR-356 if the HttpSession times out any WebSocket that was created with that HttpSession and an authenticated user should be forcibly closed. This means that if we are actively chatting in our application and are not using the HttpSession, then we will also disconnect from our conversation!

웹소켓 사용
WebSocket Usage

WebSocket Sample은 웹소켓과 스프링세션을 어떻게 통합시키는지에 대한 샘플을 제공합니다. 우리는 다음 어쩌고 기초적인 통합 단계를 따를수있고, 세부적인 것은 웹소켓 가이드를 참고하세요. (중복된 말이라 대충 의역 ;; )

The WebSocket Sample provides a working sample on how to integrate Spring Session with WebSockets. You can follow the basic steps for integration below, but you are encouraged to follow along with the detailed WebSocket Guide when integrating with your own application:

HttpSession 통합
HttpSession Integration

웹소켓 통합전에, HttpSession Integration을 먼저 해야 합니다.

Before using WebSocket integration, you should be sure that you have HttpSession Integration working first.

스프링 설정
Spring Configuration

일반적인 스프링 웹소켓 어플리케이션에서 사용자는 AbstractWebSocketMessageBrokerConfigurer를 상속할 것입니다. 예를 들어서, 설정은 다음과 같이 보여질 것입니다 :

In a typical Spring WebSocket application users would extend AbstractWebSocketMessageBrokerConfigurer. For example, the configuration might look something like the following:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig
                extends AbstractWebSocketMessageBrokerConfigurer {

        public void registerStompEndpoints(StompEndpointRegistry registry) {
                registry.addEndpoint("/messages")
                                .withSockJS();
        }

        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
                registry.enableSimpleBroker("/queue/", "/topic/");
                registry.setApplicationDestinationPrefixes("/app");
        }
}

우리는 스프링 세션의 웹소켓 지원을 사용하기 위해, 쉽게 우리의 설정을 업데이트할 수 있을 것입니다.

We can easily update our configuration to use Spring Session’s WebSocket support. For example:

src/main/java/samples/config/WebSocketConfig.java
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig
          extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> { (1)

        protected void configureStompEndpoints(StompEndpointRegistry registry) { (2)
                registry.addEndpoint("/messages")
                                .withSockJS();
        }

        public void configureMessageBroker(MessageBrokerRegistry registry) {
                registry.enableSimpleBroker("/queue/", "/topic/");
                registry.setApplicationDestinationPrefixes("/app");
        }
}

스프링 세션의 지원을 얻기 위해, 우리는 다음의 두가지를 바꿔줄 것입니다.

To hook in the Spring Session support we only need to change two things:

1
AbstractWebSocketMessageBrokerConfigurer를 상속하는 대신에, AbstractSessionWebSocketMessageBrokerConfigurer를 상속해줄 것입니다.
Instead of extending AbstractWebSocketMessageBrokerConfigurer we extend AbstractSessionWebSocketMessageBrokerConfigurer
2
우리는 registerStompEndpoints 메소드를 configureStompEndpoints로 이름을 바꿔줄 것입니다.
We rename the registerStompEndpoints method to configureStompEndpoints

이 내부에서(behind the scene) AbstractSessionWebSocketMessageBrokerConfigurer 가 무엇을 하고 있을까요?
What does AbstractSessionWebSocketMessageBrokerConfigurer do behind the scenes?

  • WebSocketConnectHandlerDecoratorFactoryWebSocketHandlerDecoratorFactory 로서 WebSocketTransportRegistration에 추가됩니다. . 이것은 WebSocketSession를 포함하는 커스텀 SessionConnectEvent가 fired된다는 것을 보장합니다. (약간 애매했다) 스프링 세션이 종료될 때 열려있는 웹소켓커넥션을 종료시키는데 WebSocketSession 필요합니다.

    WebSocketConnectHandlerDecoratorFactory is added as a WebSocketHandlerDecoratorFactory to WebSocketTransportRegistration. This ensures a custom SessionConnectEvent is fired that contains the WebSocketSession. The WebSocketSession is necessary to terminate any WebSocket connections that are still open when a Spring Session is terminated.

  • SessionRepositoryMessageInterceptorHandshakeInterceptor로써 모든 StompWebSocketEndpointRegistration에 추가됩니다. 이것은 마지막 접근된 시간을 수정하기 위해, 세션이 웹소켓 프로퍼티에 추가된다는 것을 보장합니다.

    SessionRepositoryMessageInterceptor is added as a HandshakeInterceptor to every StompWebSocketEndpointRegistration. This ensures that the Session is added to the WebSocket properties to enable updating the last accessed time.

  • SessionRepositoryMessageInterceptorChannelInterceptor로써, 우리의 인바운드 ChannelRegistration에 추가됩니다. 이것은 인바운드 메시지가 수신되는 매시간과, 스프링세션에 접근되는 마지막시간이 updated됨을 보장합니다.

    SessionRepositoryMessageInterceptor is added as a ChannelInterceptor to our inbound ChannelRegistration. This ensures that every time an inbound message is received, that the last accessed time of our Spring Session is updated.

  • WebSocketRegistryListener는 스프링 빈으로써 생성됩니다. 이것은 웹소켓 코넥션에 해당하는 모든 세션 아이디의 매핑을 가지고 있음을 보장합니다. 이 매핑을 가지고 있음으로써, 우리는 스프링 세션(http session)이 종료될 때 모든 웹소켓을 닫을 수가 있습니다.

    WebSocketRegistryListener is created as a Spring Bean. This ensures that we have a mapping of all of the Session id to the corresponding WebSocket connections. By maintaining this mapping, we can close all the WebSocket connections when a Spring Session (HttpSession) is terminated.

API 문서
API Documentation

당신은 완전한 Javadoc 온라인 문서를 볼 수가 있습니다. 핵심 API가 다음과 같이 설명되었습니다.:

You can browse the complete Javadoc online. The key APIs are described below:

Session

A Session 은 단순화된 이름값쌍의 Map 입니다..

A Session is a simplified Map of name value pairs.

일반적인 사용은 다음과 같을 것입니다.

Typical usage might look like the following:

public class RepositoryDemo<S extends Session> {
    private SessionRepository<S> repository; (1)

    public void demo() {
        S toSave = repository.createSession(); (2)

        (3)
        User rwinch = new User("rwinch");
        toSave.setAttribute(ATTR_USER, rwinch);

        repository.save(toSave); (4)

        S session = repository.getSession(toSave.getId()); (5)

        (6)
        User user = session.getAttribute(ATTR_USER);
        assertThat(user).isEqualTo(rwinch);
    }

    // ... setter methods ...
}
1
SessionRepository인스턴스를 Session를 상속하는 제너릭 타입S로 생성합니다. 제너릭타입은 우리의 클래스에 선언되었습니다.
We create a SessionRepository instance with a generic type, S, that extends Session. The generic type is defined in our class.
2
우리는 SessionRepository를 사용하여 새로운 Session을 만들 것이고 이것을 S타입 변수 에 할당할 것입니다.
We create a new Session using our SessionRepository and assign it to a variable of type S.
3
Session와 상호작용할 것입니다. 예를 들어서, 우리는 UserSession에 저장할 것입니다.
We interact with the Session. In our example, we demonstrate saving a User to the Session.
4
우리는 이제 Session을 저장할 것입니다. 이것이 제너릭 타입 S를 필요로 했던 이유입니다. SessionRepository는 같은 SessionRepository를 사용하여 Session 인스턴스만을 저장하고 불러오는 것을 허용합니다. 이것은 SessionRepository가 구체적인 최적화 구현체를 만드는 것을 허용합니다. (i.e. 오직 바뀐 속성만 쓰기)
We now save the Session. This is why we needed the generic type S. The SessionRepository only allows saving Session instances that were created or retrieved using the same SessionRepository. This allows for the SessionRepository to make implementation specific optimizations (i.e. only writing attributes that have changed).
5
우리는 SessionRepository에서 Session을 얻어옵니다.
We retrieve the Session from the SessionRepository.
6
우리는 우리의 속성을 특별히 형변환할 필요없이, Session에서 영속화된 User를 얻습니다.
We obtain the persisted User from our Session without the need for explicitly casting our attribute.

세션만기
ExpiringSession

ExpiringSessionSession인스턴스만기에 관한 속성을 제공하여, Session을 확장합니다. 만기정보가 필요하지 않다면, 단순히 Session API를 제공하는 것이 선호됩니다.

An ExpiringSession extends a Session by providing attributes related to the Session instance’s expiration. If there is no need to interact with the expiration information, prefer using the more simple Session API.

일반적 사용은 다음과 같습니다 :

Typical usage might look like the following:

public class ExpiringRepositoryDemo<S extends ExpiringSession> {
    private SessionRepository<S> repository; (1)

    public void demo() {
        S toSave = repository.createSession(); (2)
        // ...
        toSave.setMaxInactiveIntervalInSeconds(30); (3)

        repository.save(toSave); (4)

        S session = repository.getSession(toSave.getId()); (5)
        // ...
    }

    // ... setter methods ...
}
1
우리는 SessionRepository인스턴스를 ExpiringSession를 상속하는 제너릭타입 S으로 생성할 것입니다. 이 제너릭타입은 우리의 클래스 안에서 정의되었습니다.
We create a SessionRepository instance with a generic type, S, that extends ExpiringSession. The generic type is defined in our class.
2
우리는 SessionRepository를 사용하여서, 새로운 ExpiringSession을 만들고 이것을 타입S의 변수에 할당할 것입니다.
We create a new ExpiringSession using our SessionRepository and assign it to a variable of type S.
3
우리는 ExpiringSession과 상호작용할 것입니다. 이 예제에서는, 만기시간을 수정하고, ExpiringSession이 만기전 inactive하게 됨을 보여줍니다.
We interact with the ExpiringSession. In our example, we demonstrate updating the amount of time the ExpiringSession can be inactive before it expires.
4
우리는 이제 Session을 저장할 것입니다. 이것이 제너릭 타입 S를 필요로 했던 이유입니다. SessionRepository는 같은 SessionRepository를 사용하여 Session 인스턴스만을 저장하고 불러오는 것을 허용합니다. 이것은 SessionRepository가 구체적인 최적화 구현체를 만드는 것을 허용합니다. (i.e. 오직 바뀐 속성만 쓰기). ExpiringSession이 저장될 때, 마지막으로 접근된 시간이 자동적으로 updated될 것입니다.
We now save the ExpiringSession. This is why we needed the generic type S. The SessionRepository only allows saving ExpiringSession instances that were created or retrieved using the same SessionRepository. This allows for the SessionRepository to make implementation specific optimizations (i.e. only writing attributes that have changed). The last accessed time is automatically updated when the ExpiringSession is saved.
5
우리는 SessionRepository로부터 ExpiringSession 를 얻을 것입니다. 만약 ExpiringSession가 만기되면 결과는 null이 될 것입니다.
We retrieve the ExpiringSession from the SessionRepository. If the ExpiringSession were expired, the result would be null.

SessionRepository

SessionRepositorySession인스턴스의 생성, 찾기, 영속화하는 책임이 있습니다.

A SessionRepository is in charge of creating, retrieving, and persisting Session instances.

가능하다면, 개발자들은 직접적으로 SessionRepositorySession과 상호작용하지 말아야 합니다. 대신에 SessionRepository과 상호작용하거나 SessionHttpSession and WebSocket통합을 통해 간접적으로 상호작용하는 편이 선호됩니다.
If possible, developers should not interact directly with a SessionRepository or a Session. Instead, developers should prefer interacting with SessionRepository and Session indirectly through the HttpSession and WebSocket integration.

RedisOperationsSessionRepository

RedisOperationsSessionRepository 은 스프링 데이터의 RedisOperations를 사용하여 구현된 SessionRepository 입니다. 웹 환경에서 이것은 일반적으로 SessionRepositoryFilter와 조합됩니다. 이 구현체는 SessionMessageListener를 통해 SessionDestroyedEvent를 지원합니다.

RedisOperationsSessionRepository is a SessionRepository that is implemented using Spring Data’s RedisOperations. In a web environment, this is typically used in combination with SessionRepositoryFilter. The implementation supports SessionDestroyedEvent through SessionMessageListener.

RedisOperationsSessionRepository 인스턴스화하기
Instantiating a RedisOperationsSessionRepository

어떻게 새로운 인스턴스가 만들어지는 지 다음의 예제에서 볼 수가 있습니다 :

A typical example of how to create a new instance can be seen below:

JedisConnectionFactory factory = new JedisConnectionFactory();
SessionRepository<? extends ExpiringSession> repository =
        new RedisOperationsSessionRepository(factory);

RedisConnectionFactory를 생성하는 더 많은 정보를 위해서 , 스프링 데이터 레디스 레퍼런스를 보세요 (번역하였다^^)

For additional information on how to create a RedisConnectionFactory, refer to the Spring Data Redis Reference.

Storage Details

레디스에 저장된 각각의 세션은 해쉬입니다. 각각의 세셧은 HMSET 명령어를 사용하여 set되고 updated됩니다. 어떻게 각각의 세션이 저장되는 지는 다음에 나와있습니다.

Each session is stored in Redis as a Hash. Each session is set and updated using the HMSET command. An example of how each session is stored can be seen below.

HMSET spring:session:sessions:<session-id> creationTime 1404360000000 \
    maxInactiveInterval 1800 lastAccessedTime 1404360000000 \
    sessionAttr:<attrName> someAttrValue sessionAttr:<attrName2> someAttrValue2
Session Expiration

RedisOperationsSessionRepository.RedisSession.getMaxInactiveInterval()에 기반한 EXPIRE명령을 사용하여, 만기가 각각의 세션과 연관되어집니다. 예를 들자면 :

An expiration is associated to each session using the EXPIRE command based upon the RedisOperationsSessionRepository.RedisSession.getMaxInactiveInterval(). For example:

EXPIRE spring:session:sessions:<session-id> 1800

스프링 세션은 만기에 의존적이고, 레디스에서 keyspace notifications를 지워서 SessionDestroyedEvent를 fire합니다. 세션과 clearned up에 관련된 자원을 SessionDestroyedEvent가 보장합니다. 예를 들어, 스프링세션의 웹소켓 지원을 사용할 때, 레디스 만기나 이벤트를 지우는 것이 닫힐 세션과 관련된 웹소켓 코넥션을 발동(trigger)시킵니다.

Spring Session relies on the expired and delete keyspace notifications from Redis to fire a SessionDestroyedEvent. It is the SessionDestroyedEvent that ensures resources associated with the Session are cleaned up. For example, when using Spring Session’s WebSocket support the Redis expired or delete event is what triggers any WebSocket connections associated with the session to be closed.

이러한 접근의 문제는, 키가 만약 접근되지 않으면 만기된 이벤트가 fired될 때 레디스가 어떠한 보장을 하지 않는다는 것입니다. (주어 두개 나오고 좀 이상하다.ㅠ) 특별히 레디스가 만기된 키를 clean up하기 위한 백그라운드 작업이 낮은 우선순위의 일이거나 키 만기를 발동시키지 않을 때 그러합니다. 추가적인 세부사항은 레디스문서의 Timing of expired events를 보세요.

One problem with this approach is that Redis makes no guarantee of when the expired event will be fired if they key has not been accessed. Specifically the background task that Redis uses to clean up expired keys is a low priority task and may not trigger the key expiration. For additional details see Timing of expired events section in the Redis documentation.

만기된 이벤트가 보장되지 않는 것을 피하기위해서 우리는 각각의 만기될 것으로 예상되는 키에 접근이 되는 것을 보장해야 합니다. 이것이 의미하는 바는, 만약 TTL 이 key에서 만기되면, 레디스는 키를 지우고, 우리가 they key에 접근하려고 시도하면 만기된 이벤트를 fire할 것입니다. (they key?)

To circumvent the fact that expired events are not guaranteed to happen we can ensure that each key is accessed when it is expected to expire. This means that if the TTL is expired on the key, Redis will remove the key and fire the expired event when we try to access they key.

이러한 이유로, 각각의 세션 만기는 또한 분(minute)에 가깝게 파악됩니다. 이것은 백그라운드 작업이 잠재적으로 만기된 세션에 접근하게 하는 것을 허용하며, 레디스 만기된 이벤트가 좀 더 결정적인 방법(deterministic fashin)으로 fired되는 것을 보장합니다. 예를 들어 :

For this reason, each session expiration is also tracked to the nearest minute. This allows a background task to access the potentially expired sessions to ensure that Redis expired events are fired in a more deterministic fashion. For example:

SADD spring:session:expirations:<expire-rounded-up-to-nearest-minute> <session-id> EXPIRE spring:session:expirations:<expire-rounded-up-to-nearest-minute> 1860

백그라운드 작업은 그러면 각각의 키 요청에 명시적인 매핑을 사용할 것입니다. 키를 삭제하지 않고 접근하기 위해, 우리는 오직 TTL 이 만기될 때만 레디스가 키를 삭제하게 보장해야 합니다.

The background task will then use these mappings to explicitly request each key. By accessing they key, rather than deleting it, we ensure that Redis deletes the key for us only if the TTL is expired.

우리는 명시적으로 키를 지우지 않습니다. 왜냐하면 몇몇 인스턴스는 race condition으로, 만기되지 않았는데 만기되었다고 부정확하게 키를 식별하기 때문입니다. (성능을 하락시키는) distributed locks을 사용하는 것외에 만기매핑에 대한 일관성을 보장하는 방법은 없습니다. 키에 단순히 접근하게 하기위해 우리는 키에 대한 TTL 이 만기될 때 키를 삭제하는 것을 보장합니다.
We do not explicitly delete the keys since in some instances there may be a race condition that incorrectly identifies a key as expired when it is not. Short of using distributed locks (which would kill our performance) there is no way to ensure the consistency of the expiration mapping. By simply accessing the key, we ensure that the key is only removed if the TTL on that key is expired.
Optimized Writes

RedisOperationsSessionRepository에 의해 관리되는 Session 인스턴스는 변경되는 속성(properties)들을 파악하고, 오직 그러한 것들을 update합니다. 이것은 속성이 한번 쓰여지고 많이 읽혀지면, 우리는 오직 그 속성을 한번만 쓸 필요가 있다는 것을 의미합니다. 예를 들어 이전의 세션속성"sessionAttr2"가 업데이트되었다고 가정해봅시다. 다음은 저장하면서 실행됩니다.

The Session instances managed by RedisOperationsSessionRepository keeps track of the properties that have changed and only updates those. This means if an attribute is written once and read many times we only need to write that attribute once. For example, assume the session attribute "sessionAttr2" from earlier was updated. The following would be executed upon saving:

HMSET spring:session:sessions:<session-id> sessionAttr:<attrName2> newValue EXPIRE spring:session:sessions:<session-id> 1800

SessionDestroyedEvent

RedisOperationsSessionRepositorySession이 삭제되거나 만기될 때마다 SessionDestroyedEvent의 firing을 지원합니다. 이것은 Session과 관련된 자원들이 이 적절히 cleand up되는 것을 보장할 필요가 없습니다. 예를 들어서 웹소켓을 통합할 때 SessionDestroyedEvent는 active 웹소켓 코넥션을 닫을 책임을 가집니다.

RedisOperationsSessionRepository supports firing a SessionDestroyedEvent whenever a Session is deleted or when it expires. This is necessary to ensure resources associated with the Session are properly cleaned up. For example, when integrating with WebSockets the SessionDestroyedEvent is in charge of closing any active WebSocket connections.

SessionDestroyedEvent을 firing하는 것은 Redis Keyspace events를 리스닝하고 있는 SessionMessageListener을 통해서 가능합니다. 이것이 가능하게 하기 위해, 일반 명령어를 위한 레디스 키스페이스 이벤트와 만기된 이벤트가 활성화(enabled)될 필요가 있습니다. 예를 들어 :

Firing a SessionDestroyedEvent is made available through the SessionMessageListener which listens to Redis Keyspace events. In order for this to work, Redis Keyspace events for Generic commands and Expired events needs to be enabled. For example:

redis-cli config set notify-keyspace-events Egx

만약 당신이 @EnableRedisHttpSessionSessionMessageListener를 쓴다면, 필요한 레디스 키스페이스 이벤트를 활성화시키는 것은 자동으로 이루어집니다. 그러나 secured 레디스 환경에서 설정 명령어는 disabled됩니다. 이것은 스프링 세션이 당신을 위해서 레디스 키스페이스 이벤트를 설정하지 못한다는 것을 의미합니다. 자동설정을 disable하기 위해 빈으로 ConfigureRedisAction.NO_OP를 추가하세요

If you are using @EnableRedisHttpSession the SessionMessageListener and enabling the necessary Redis Keyspace events is done automatically. However, in a secured Redis enviornment the config command is disabled. This means that Spring Session cannot configure Redis Keyspace events for you. To disable the automatic configuration add ConfigureRedisAction.NO_OP as a bean.

예를 들어서 자바설정을 다음과 같이 사용할 수 있을 것입니다 :

For example, Java Configuration can use the following:

@Bean
public static ConfigureRedisAction configureRedisAction() {
    return ConfigureRedisAction.NO_OP;
}

XML 설정은 다음과 같을 수 있을 것입니다.

XML Configuraiton can use the following:

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

레디스에서 세션 보기 : Viewing the Session in Redis

redis-cli를 설치한 이후 당신은 the redis-cli를 사용하여서, 레디스에서 값을 검사할 수 있습니다. 예를 들어서 터미널에서 다음과 같이 쳐보세요 :

After installing redis-cli, you can inspect the values in Redis using the redis-cli. For example, enter the following into a terminal:

$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
2) "spring:session:expirations:1418772300000" (2)
1
이것의 접미사는 스프링 세션의 세션 식별자입니다.
The suffix of this key is the session identifier of the Spring Session.
2
이 키는 1418772300000에 삭제되는 모든 세션의 아이디를 포함하고 있습니다.
This key contains all the session ids that should be deleted at the time 1418772300000.

당신은 또한 각각의 세션의 속성을 볼 수가 있습니다.

You can also view the attributes of each session.

redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"

MapSessionRepository

MapSessionRepositoryExpiringSession의 아이디인 키와, ExpiringSession가 값인 Map 형태로 ExpiringSession 의 영속화를 허용합니다. 이 구현체는 테스트나 convenience 메커니즘으로 ConcurrentHashMap와 함께 사용될 수 있습니다. 그 대신에 , 이것은 distributed Map구현체로 사용될 수 있습니다. 이것은 Hazelcase와 함께 사용될 수 있습니다.

The MapSessionRepository allows for persisting ExpiringSession in a Map with the key being the ExpiringSession id and the value being the ExpiringSession. The implementation can be used with a ConcurrentHashMap as a testing or convenience mechanism. Alternatively, it can be used with distributed Map implementations. For example, it can be used with Hazelcast.

MapSessionRepository 인스턴스화하기
Instantiating MapSessionRepository

새로운 인스턴스를 생성하는 것은 이처럼 단순합니다 :

Creating a new instance is as simple as:

SessionRepository<? extends ExpiringSession> repository = new MapSessionRepository();

Using Spring Session and Hazlecast

Hazelcast Sample 은 완전한 어플리케이션으로, 스프링세션과 Hazelcase의 사용을 보여줍니다.. 다음으로 실행할 수 있습니다.

The Hazelcast Sample is a complete application demonstrating using Spring Session with Hazelcast. To run it use the following:

./gradlew :samples:hazelcast:tomcatRun

스프링 세션 커뮤니티
Spring Session Community

우리는 당신이 커뮤니티의 일부가 되면 기쁠 것입니다. 추가적인 정보를 다음에서 찾아보세요 .

We are glad to consider you a part of our community. Please find additional information below.

지원
Support

당신은 질문을 StackOverflow with the tag spring-session에서 할 수가 있습니다.

You can get help by asking questions on StackOverflow with the tag spring-session. Similarly we encourage helping others by answering questions on StackOverflow.

소스 코드
Source Code

우리의 소스는https://github.com/spring-projects/spring-session/에서 발견가능합니다.

Our source code can be found on github at https://github.com/spring-projects/spring-session/

이슈 트랙킹
Issue Tracking

https://github.com/spring-projects/spring-session/issues에서 하세요

We track issues in github issues at https://github.com/spring-projects/spring-session/issues

기여
Contributing

풀리퀘주시면 감사합니다. .

We appreciate Pull Requests.

라이센스
License

스프링 세션은 Apache 2.0 license의 오픈 소스 소프트웨어입니다.

Spring Session is Open Source software released under the Apache 2.0 license.

댓글