Статьи

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

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

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

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

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

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

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

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, это в первую очередь зависимости, которые я извлек:

<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, который используется для регистрации  фильтра репозитория сеанса :

import 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.