스프링 세션은 사용자의 세션 정보를 관리하기 위하여 API와 구현체를 제공합니다.
Spring Session provides an API and implementations for managing a user’s session information.
스프링 세션은 사용자의 세션정보를 관리하기 위해 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
만약 당신이 스프링세션에서 시작하기를 원한다면, 우리의 예제 어플리케이션들로 시작해보세요
If you are looking to get started with Spring Session, the best place to start is our Sample Applications.
Source | Description | Guide |
---|---|---|
스프링세션을 사용하여 Demonstrates how to use Spring Session to replace the |
||
XML기반의 설정을 사용하고 스프링세션을 사용하여 Demonstrates how to use Spring Session to replace the |
||
스프링세션을 어떻게 스프링부트에서 사용하는지 보여줍니다. Demonstrates how to use Spring Session with Spring Boot. |
||
존재하는 스프링시큐리티 어플리케션과 스프링세션을 어떻게 같이 사용하는지 보여줍니다. Demonstrates how to use Spring Session with an existing Spring Security application. |
||
헤더와 함께 인증을 지원하는 REST 어플리케이션에서 어떻게 스프링 세션을 사용하는지 보여줍니다. Demonstrates how to use Spring Session in a REST application to support authenticating with a header. |
||
스프링세션을 사용하여서 어떻게 여러개의 동시 브라우저 세션(구글 계정같은) 들을 관리하는지 보여줍니다. Demonstrates how to use Spring Session to manage multiple simultaneous browser sessions (i.e Google Accounts). |
||
스프링세션과 웹소켓을 어떻게 사용하는지 보여줍니다 . Demonstrates how to use Spring Session with WebSockets. |
||
스프링 세션과 Hazelcast를 어떻게 사용하는지 보여줍니다. Demonstrates how to use Spring Session with Hazelcast. |
TBD |
스프링 세션은 HttpSession
과의 투명한 통합을 제공합니다.이것은 개발자가 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
HttpSession
을 사용하기 이전에(의역 조금 추가), 서블릿필터를 추가해줌으로써 HttpSession
과 스프링세션을 활성화시킬 수 있습니다.
Using Spring Session with HttpSession
is enabled by adding a Servlet Filter before anything that uses the HttpSession
.
이 섹션은 자바 설정기반을 사용하여, 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.
요청 의존성을 추가한 이후에, 스프링 설정을 생성할 수 있습니다. 스프링설정은 서블릿필터를 만들어내는 책임이 있으며, 이 필터는 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.
우리의 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
.
이 섹션은 자바 설정기반을 사용하여, 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.
|
요청 의존성을 추가한 이후에, 스프링 설정을 생성할 수 있습니다. 스프링설정은 서블릿필터를 만들어내는 책임이 있으며, 이 필터는 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.
|
우리의 Spring Configuration 은 필터를 구현하는 springSessionRepositoryFilter
라 불리는 스프링 빈에 의해 생성됩니다.
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:
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 .
|
이 섹션은 어떻게 레디스를 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.
|
필요한 의존성을 추가한 이후에 우리의 스프링 설정을 생성할 수 있습니다. 이 스프링 설정은 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:
<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.
|
우리의 스프링 설정은 Filter
를 구현하는 springSessionRepositoryFilter
라는 이름의 스프링빈을 생성할 것입니다. springSessionRepositoryFilter
빈은 HttpSession
을 스프링세션에 의해 지원(backed by)되는 커스텀 구현체로 바꿔주는 책임이 있습니다.
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
설정을 불러오게 해줘야 합니다.
<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:
<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>
DelegatingFilterProxy 는 springSessionRepositoryFilter
라는 이름으로 빈을 찾아서, 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.
다행스럽게도 HttpSession
와 HttpServletRequest
( 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
구현체를 사용하는 것을 보장할 수가 있습니다. 이것은 스프링 세션의 SessionRepositoryFilter
가 HttpSession
와 상호작용하는 것들 이전에 놓여져야하는것이 왜 중요한지 강조합니다.
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
.
스프링 세션은 단일 브라우저 인스턴스에서 여러개의 세션을 지원할 수 있습니다. 이것은 같은 브라우저 인스턴스에서 (구글계정처럼) 여러개의 사용자를 인증하는 것을 지원합니다.
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:
HttpSessionManager sessionManager =
(HttpSessionManager) httpRequest.getAttribute(HttpSessionManager.class.getName());
우리는 이제 이것을 사용하여, 다른 세션을 추가할 URL을 생성할 수가 있을 것입니다.
We can now use it to create a URL to add another session.
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에서 세션별명을 명시해주는 것의 좋은 점은 다른 액티브세션들과 함께 여러개의 탭을 가질 수가 있다는 것입니다. 나쁜 것은 우리 어플리케이션의 모든 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:
-->
<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>
스프링 세션은 헤더에 제공되는 세션을 허용케 함으로써, 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.
|
요청된 의존성을 추가한 이후에, 우리는 스프링 설정을 생성할 것입니다. 스프링 설정은 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.
|
우리의 스프링 설정은 Filter
를 구현하는 springSessionRepositoryFilter
라는 이름의 스프링빈을 생성할 것입니다. springSessionRepositoryFilter
빈은 HttpSession
을 스프링세션에 의해 지원(backed by)되는 커스텀 구현체로 바꿔주는 책임이 있습니다.
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:
@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:
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
우리의 클래스의 이름 (Initializer)은 중요하지 않고,
AbstractHttpSessionApplicationInitializer 를 상속한 것이 중요합니다.
The name of our class (Initializer) does not matter. What is important is that we extend
AbstractHttpSessionApplicationInitializer .
|
스프링 세션은 스프링 웹 소켓지원에의 투명한 통합을 제공합니다.
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.
|
그래서 왜 우리가 웹소켓을 사용할 때 스프링 세션을 필요로 하는가요?
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 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 Integration을 먼저 해야 합니다.
Before using WebSocket integration, you should be sure that you have HttpSession Integration working first.
일반적인 스프링 웹소켓 어플리케이션에서 사용자는 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:
@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
|
AbstractSessionWebSocketMessageBrokerConfigurer
가 무엇을 하고 있을까요?
AbstractSessionWebSocketMessageBrokerConfigurer
do behind the scenes?
-
WebSocketConnectHandlerDecoratorFactory
은WebSocketHandlerDecoratorFactory
로서WebSocketTransportRegistration
에 추가됩니다. . 이것은WebSocketSession
를 포함하는 커스텀SessionConnectEvent
가 fired된다는 것을 보장합니다. (약간 애매했다) 스프링 세션이 종료될 때 열려있는 웹소켓커넥션을 종료시키는데WebSocketSession
필요합니다.WebSocketConnectHandlerDecoratorFactory
is added as aWebSocketHandlerDecoratorFactory
toWebSocketTransportRegistration
. This ensures a customSessionConnectEvent
is fired that contains theWebSocketSession
. TheWebSocketSession
is necessary to terminate any WebSocket connections that are still open when a Spring Session is terminated. -
SessionRepositoryMessageInterceptor
는HandshakeInterceptor
로써 모든StompWebSocketEndpointRegistration
에 추가됩니다. 이것은 마지막 접근된 시간을 수정하기 위해, 세션이 웹소켓 프로퍼티에 추가된다는 것을 보장합니다.SessionRepositoryMessageInterceptor
is added as aHandshakeInterceptor
to everyStompWebSocketEndpointRegistration
. This ensures that the Session is added to the WebSocket properties to enable updating the last accessed time. -
SessionRepositoryMessageInterceptor
는ChannelInterceptor
로써, 우리의 인바운드ChannelRegistration
에 추가됩니다. 이것은 인바운드 메시지가 수신되는 매시간과, 스프링세션에 접근되는 마지막시간이 updated됨을 보장합니다.SessionRepositoryMessageInterceptor
is added as aChannelInterceptor
to our inboundChannelRegistration
. 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.
당신은 완전한 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 와 상호작용할 것입니다. 예를 들어서, 우리는 User 를 Session 에 저장할 것입니다.
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
는 Session
인스턴스만기에 관한 속성을 제공하여, 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
SessionRepository
은 Session
인스턴스의 생성, 찾기, 영속화하는 책임이 있습니다.
A SessionRepository
is in charge of creating, retrieving, and persisting Session
instances.
SessionRepository
나 Session
과 상호작용하지 말아야 합니다. 대신에 SessionRepository
과 상호작용하거나 Session
에 HttpSession and WebSocket통합을 통해 간접적으로 상호작용하는 편이 선호됩니다.
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
.
어떻게 새로운 인스턴스가 만들어지는 지 다음의 예제에서 볼 수가 있습니다 :
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
RedisOperationsSessionRepository
는 Session
이 삭제되거나 만기될 때마다 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
만약 당신이 @EnableRedisHttpSession
와 SessionMessageListener
를 쓴다면, 필요한 레디스 키스페이스 이벤트를 활성화시키는 것은 자동으로 이루어집니다. 그러나 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
MapSessionRepository
는ExpiringSession
의 아이디인 키와, 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.
새로운 인스턴스를 생성하는 것은 이처럼 단순합니다 :
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
우리는 당신이 커뮤니티의 일부가 되면 기쁠 것입니다. 추가적인 정보를 다음에서 찾아보세요 .
We are glad to consider you a part of our community. Please find additional information below.
당신은 질문을 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.
우리의 소스는https://github.com/spring-projects/spring-session/에서 발견가능합니다.
Our source code can be found on github at https://github.com/spring-projects/spring-session/
We track issues in github issues at https://github.com/spring-projects/spring-session/issues
풀리퀘주시면 감사합니다. .
We appreciate Pull Requests.
스프링 세션은 Apache 2.0 license의 오픈 소스 소프트웨어입니다.
Spring Session is Open Source software released under the Apache 2.0 license.