在Servlet过滤器内部调用容器的会话对象而不是GemFire的会话对象

时间:2018-09-12 14:11:17

标签: java spring spring-session gemfire spring-data-gemfire

从自定义Servlet过滤器尝试访问GemFire会话对象时,它将采用容器的会话对象。会话对象的类型:

org.apache.catalina.session.StandardSessionFacade@517957e2

但是从Controller开始,它工作正常。会话对象的类型为:               org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper$HttpSessionWrapper@5afe18ce

关于我们如何配置GemFire:

我们有旧版零售应用程序。最重要的是,我们使用了2.0.5版本的GemFire。在 webappintializer 启动中,

AnnotationConfigWebApplicationContext rootContext = 
    new AnnotationConfigWebApplicationContext();

rootContext.register(GemfireConfig.class,RootConfig.class, SecurityConfig.class);

由于未将springSessionRepositoryFilter Bean添加到过滤器链中,因此我们不得不使用以下命令向DelegatingFilterProxy明确注册过滤器:

FilterRegistration.Dynamic springSessionRepositoryFilter = 
    container.addFilter("springSessionRepositoryFilter", DelegatingFilterProxy.class);

springSessionRepositoryFilter.addMappingForUrlPatterns(
    EnumSet.allOf(DispatcherType.class), false, "/*");

在数据处理方面,为了获取会话对象,我们有一个getSession方法,该方法返回一个会话对象:

ServletRequestAttributes attr = 
    (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();

HttpSession session = attr.getRequest().getSession();

当我们从getSession()调用Controller方法时,它按设计工作是绝对正常的。但是从Servlet过滤器调用相同的对象最终将获得Container创建的会话对象。

非常感谢您的帮助。

根据@John Blum的评论进行了重做,但仍然面临相同的问题。

1 个答案:

答案 0 :(得分:0)

简而言之,为了Spring Session,特别是Spring Session for Pivotal GemFire(SSDG)的工作,SessionRepositoryFilterJavadoc,{{3} })向(Web)应用程序容器(例如Apache Tomcat,Eclipse Jetty等)注册时,必须是过滤器链中的第一个 Servlet过滤器。

否则,如果 Spring Session的 SessionRepositoryFilter不是过滤器链中的第一个Servlet过滤器,则 Spring Session 将不会拦截HTTP请求(至今),将无法利用由HttpServletRequest来替换Container会话的机会(通过将SessionRepositoryFilter.SessionRepositoryRequestWrapper换成Session,请参见Source)来替换Container会话。使用由SessionRepository实现确定的适当的提供程序(例如,带有SSDG的GemFire,例如> Spring Session )。SessionRepositoryFilterhere)上进行设置。

您的Spring Web MVC应用程序Controller起作用的原因是,Java EE Servlet规范/容器保证在用HTTP请求调用任何Servlet(即HttpServletRequest)之前,所有Servlet过滤器都被调用。 。而且,由于Spring Web MVC DispatcherServlet是正确的HttpServlet,并且负责调用您的应用程序定义的Spring Web MVC Controllers,因此可以保证应用程序Controllers可以看到“已替换的” HTTP请求(扩展名为HTTP会话对象)。

那么,一些家政用品...我(不确定)您的意思是什么

  1. 2.0.5版本的GemFire。 2.0.5是指 Pivotal GemFire春季会议的最新版本

  2. 还有webappinitializer吗?

对于#2,您是说专门创建了一个Spring here来手动手动注册SessionRepositoryFilter(如上面的代码片段所示)吗?

您知道 Spring Session 已经提供了此类吗?WebApplicationInitializer

该类负责使用Spring的SessionRepositoryFilter类(o.s.session.web.context.AbstractHttpServletApplicationInitializer,然后是herehere来注册DelegatingFilterProxy(注意{{1} }实例变量,默认为insertBeforeOtherFilters),正确的顺序为here,具体来说,here)。

有趣的是,您似乎在上述“过滤器”注册代码的片段中正在做相同或相似的事情。

注意:此(Servlet容器的程序配置)仅在Servlet 3.0容器及更高版本中起作用。

您可以看到 Spring Session的 true如何在here中使用,例如samples。有关AbstractHttpServletApplicationInitializer的更多详细信息,请参见样本的相应here

我注意到,关于Spring Initializer类注册(以DelegatingFilterProxy bean命名,名为“ springSessionRepositoryFilter”)的另一件事是,您将SessionRepositoryFilter作为第二个DelegatingFilterProxy.class的参数,如下所示...

servletContext.addFilter("filterName", <FilterType>);

但是, Spring Session (核心)本身实际上guide docs(具有“ springSessionRepositoryFilter” bean名称)是Spring FilterRegistration.Dynamic springSessionRepositoryFilter = container.addFilter("springSessionRepositoryFilter", DelegatingFilterProxy.class); 类和constructs and initializes的实例注册时使用DelegatingFilterProxy方法(第二个参数)的“实例”。

我怀疑ServletContext.addFilter(..) API本身在构造/初始化实例时仅使用Spring ServletContext.addFilter(..)类的默认构造函数,这可能是问题的根源,尤其是在以编程方式注册Servlet Filter时

令人回味的食物。

希望这会有所帮助!