在Servlet过滤器中调用Container的会话对象而不是GemFire的会话对象

问题描述 投票:0回答:2

在尝试访问GemFire会话对象时,从自定义Servlet过滤器,它将取而代之的是Container的会话对象。会话对象的类型如下:

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的评论重写,但仍面临同样的问题。

java spring spring-session gemfire spring-data-gemfire
2个回答
0
投票

简而言之,为了使Spring Session,特别是Spring Session for Pivotal GemFire(SSDG)能够完成它的工作,SessionRepositoryFilterJavadocSource)必须是在您的(Web)应用程序容器中注册时过滤器链中的第一个Servlet过滤器(例如, Apache Tomcat,Eclipse Jetty等)。

否则,如果Spring Session的SessionRepositoryFilter不是过滤器链中的第一个Servlet过滤器,那么Spring Session将不会截获HTTP请求(还),并且无法利用它来替换Container会话(通过包装HttpServletRequest)与SessionRepositoryFilter.SessionRepositoryRequestWrapper一起使用here与Spring会话提供的Session使用适当的提供者(例如像带有SSDG的GemFire),由SessionRepositorySessionRepositoryFilter)设置的here实现确定。

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

所以,一些家务用品......我不是(确切)确定你的意思:

  1. 2.0.5版本的GemFire。 2.0.5指的是Pivotal GemFire的最新/当前版本的Spring Session。
  2. webappinitializer

对于#2,你的意思是你专门创建了一个Spring WebApplicationInitializer来手动显式注册SessionRepositoryFilter(如上面的代码片段所示)?

你知道Spring Session已经提供了这样一个类... o.s.session.web.context.AbstractHttpServletApplicationInitializer

这个类负责使用Spring的SessionRepositoryFilter类(DelegatingFilterProxy,然后是herehere(注意here实例变量,默认为insertBeforeOtherFilters)注册true,并按照正确的顺序,here,具体来说,here)。

有趣的是,看起来你在上面的Filter注册码片段中做了相同或类似的事情。

注意:这(Servlet容器的程序配置)仅适用于Servlet 3.0容器及更高版本。

你可以看看Spring Session qazxsw poi如何在qazxsw poi中使用,例如,AbstractHttpServletApplicationInitializer。关于samples的更多细节在样本的相应here中。

关于你的Spring Initializer类注册(以guide docs bean命名,命名为“springSessionRepositoryFilter”)的一个不同之处,我注意到,你正在传递DelegatingFilterProxy作为SessionRepositoryFilter的第二个参数,如此处所示......

DelegatingFilterProxy.class

但是,Spring Session(核心)本身实际上是servletContext.addFilter("filterName", <FilterType>);(带有“springSessionRepositoryFilter”bean名称)Spring FilterRegistration.Dynamic springSessionRepositoryFilter = container.addFilter("springSessionRepositoryFilter", DelegatingFilterProxy.class); 类和constructs and initializes的一个实例,即“实例”到DelegatingFilterProxy方法(第2个参数)的注册。

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

值得深思。

希望这可以帮助!


0
投票

在尝试完建议后,问题仍然存在。现在,我们不再使用ServletContext.addFilter(..)的单独注册。我们现在使用:

DelegatingProxyFilter

删除了springSessionRepositoryFilter的显式注册。

当我们查看堆栈跟踪时,我们可以看到首先调用此过滤器。因此,过滤器链的顺序似乎完好无损。

我们面临问题的过滤器随后被调用。即使没有提到的变化,这也是相同的行为。

但是,过滤器中的会话对象来自容器。

© www.soinside.com 2019 - 2024. All rights reserved.