使用spring-session外部化Spring-boot应用程序的会话状态

Spring-session是一个非常酷的新项目,旨在提供一种更简单的方法来管理基于Java的Web应用程序中的会话。 我最近在spring-session中探索的功能之一是它支持外部化会话状态的方式,而无需费心诸如Tomcat或Jetty之类的特定Web容器的内部。

为了测试spring-session,我使用了购物车类型的应用程序(可在此处获得 ),该应用程序通过将添加到购物车中的项保留为session属性来大量使用session,如以下屏幕截图所示:



店铺首页

ShopFrontCart

首先考虑没有Spring会话的场景。 所以这就是我公开我的应用程序的方式:

nginxLoadBalanced

我正在使用nginx在该应用程序的两个实例之间实现负载平衡。 使用Spring boot可以很容易地运行此设置,我通过两个不同的服务器端口启动了该应用程序的两个实例:

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接收到一个会话id,它无法识别,则行为是创建一个新会话。

将Spring会话引入应用程序

有一些特定于容器的方法来引入外部会话存储– 这里是一个示例,其中Redis被配置为Tomcat的存储。 Pivotal Gemfire提供了一个模块来外部化Tomcat的会话状态

使用Spring-session的好处是根本不依赖容器-保持会话状态成为应用程序的考虑因素。 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-session用于会话支持的配置,请注意特定于Spring Boot的FilterRegistrationBean,用于注册会话存储库过滤器

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使用公共Redis存储对两个不同的Spring-Boot应用程序进行负载平衡,则该应用程序将正常运行,而不管实例处理请求的情况如何。 我期待进一步完善这个出色的新项目。

  • 使用Spring会话的示例应用程序可在此处获得 :https://github.com/bijukunjummen/shopping-cart-cf-app.git

翻译自: https://www.javacodegeeks.com/2014/11/externalizing-session-state-for-a-spring-boot-application-using-spring-session.html