Статьи

Вывод состояния сеанса для приложения Spring-boot с использованием Spring-сеанса

Spring-session — это очень крутой новый проект, цель которого — предоставить более простой способ управления сеансами в веб-приложениях на основе Java. Одной из особенностей, которые я недавно исследовал в Spring-session, было то, что он поддерживает экстернализацию состояния сеанса без необходимости работать с внутренними компонентами определенных веб-контейнеров, таких как Tomcat или Jetty.

Чтобы протестировать весеннюю сессию, я использовал приложение типа корзины для покупок (доступно здесь ), которое интенсивно использует сессию, сохраняя элементы, добавленные в корзину, в качестве атрибута сессии, как видно из этих снимков экрана:

ShopFrontHome

ShopFrontCart

Рассмотрим сначала сценарий без весенней сессии. Вот как я выставил свое приложение:

nginxLoadBalanced

Я использую nginx для балансировки нагрузки между двумя экземплярами этого приложения. Эту настройку очень легко запустить с помощью Spring-загрузки, я запустил два экземпляра приложения, используя два разных серверных порта:

1
2
mvn spring-boot:run -Dserver.port=8080
mvn spring-boot:run -Dserver.port=8082

и это мой nginx.conf для балансировки нагрузки между этими двумя экземплярами:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
events {
    worker_connections  1024;
}
http {
    upstream sessionApp {
        server localhost:8080;
        server localhost:8082;
    }
 
    server {
        listen 80;
 
        location / {
            proxy_pass http://sessionApp;
        }      
    }
}

Я отображаю номер порта приложения в нижнем колонтитуле, чтобы показать, какой экземпляр обрабатывает запрос.

Если бы я ничего не делал для перемещения состояния сеанса из приложения, то поведение приложения было бы неустойчивым, поскольку сеанс, установленный в одном экземпляре приложения, не был бы распознан другим экземпляром, особенно если Tomcat получает сеанс Если он не распознает, то поведение заключается в создании нового сеанса.

Введение весенней сессии в приложение

Существуют специфические для контейнера способы представления внешних хранилищ сеансов. Один из примеров здесь , где Redis настроен как хранилище для Tomcat. Pivotal Gemfire предоставляет модуль для экстернализации состояния сеанса Tomcat .

Преимущество использования Spring-сеанса в том, что он вообще не зависит от контейнера — поддержание состояния сеанса становится проблемой приложения. Инструкции по настройке приложения для использования сеанса Spring подробно изложены на сайте сеанса Spring , просто для краткого изложения того, как я сконфигурировал свое приложение Spring Boot, это в первую очередь зависимости, которые я извлек:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<dependency>
 <groupId>org.springframework.session</groupId>
 <artifactId>spring-session</artifactId>
 <version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
 <groupId>org.springframework.session</groupId>
 <artifactId>spring-session-data-redis</artifactId>
 <version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
 <groupId>org.springframework.data</groupId>
 <artifactId>spring-data-redis</artifactId>
 <version>1.4.1.RELEASE</version>
</dependency>
<dependency>
 <groupId>redis.clients</groupId>
 <artifactId>jedis</artifactId>
 <version>2.4.1</version>
</dependency>

и моя конфигурация для использования Spring-сессии для поддержки сеанса, обратите внимание на специфичный для Spring Boot FilterRegistrationBean, который используется для регистрации фильтра репозитория сеанса :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
mport org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
 
import java.util.Arrays;
 
@Configuration
@EnableRedisHttpSession
public class SessionRepositoryConfig {
 
 @Bean
 @Order(value = 0)
 public FilterRegistrationBean sessionRepositoryFilterRegistration(SessionRepositoryFilter springSessionRepositoryFilter) {
  FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
  filterRegistrationBean.setFilter(new DelegatingFilterProxy(springSessionRepositoryFilter));
  filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
  return filterRegistrationBean;
 }
 
 @Bean
 public JedisConnectionFactory connectionFactory() {
  return new JedisConnectionFactory();
 }
}

И это все! волшебным образом теперь вся сессия обрабатывается Spring-сессией и аккуратно выводится на Redis.

Если бы мне пришлось повторить мою предыдущую конфигурацию использования nginx для балансировки нагрузки двух разных приложений Spring-Boot с использованием общего хранилища Redis, приложение просто работает независимо от экземпляра, обрабатывающего запрос. Я с нетерпением жду дальнейших улучшений этого превосходного нового проекта.

  • Пример приложения, использующего Spring-сессию, доступен здесь : https://github.com/bijukunjummen/shopping-cart-cf-app.git.