在尝试访问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的评论重写,但仍面临同样的问题。
简而言之,为了使Spring Session,特别是Spring Session for Pivotal GemFire(SSDG)能够完成它的工作,SessionRepositoryFilter
(Javadoc,Source)必须是在您的(Web)应用程序容器中注册时过滤器链中的第一个Servlet过滤器(例如, Apache Tomcat,Eclipse Jetty等)。
否则,如果Spring Session的SessionRepositoryFilter
不是过滤器链中的第一个Servlet过滤器,那么Spring Session将不会截获HTTP请求(还),并且无法利用它来替换Container会话(通过包装HttpServletRequest
)与SessionRepositoryFilter.SessionRepositoryRequestWrapper
一起使用here与Spring会话提供的Session
使用适当的提供者(例如像带有SSDG的GemFire),由SessionRepository
(SessionRepositoryFilter
)设置的here实现确定。
您的Spring Web MVC应用程序Controller
工作的原因是,Java EE Servlet规范/容器保证在使用HTTP请求(即HttpServletRequest
)调用任何Servlet之前调用所有Servlet过滤器。而且,由于Spring Web MVC DispatcherServlet
是一个合适的HttpServlet
并负责调用应用程序定义的Spring Web MVC Controllers
,因此应用程序Controllers
可以保证看到“替换”的HTTP请求(以及扩展名为HTTP会话对象)。
所以,一些家务用品......我不是(确切)确定你的意思:
2.0.5
版本的GemFire。 2.0.5
指的是Pivotal GemFire的最新/当前版本的Spring Session。webappinitializer
?对于#2,你的意思是你专门创建了一个Spring WebApplicationInitializer
来手动显式注册SessionRepositoryFilter
(如上面的代码片段所示)?
你知道Spring Session已经提供了这样一个类... o.s.session.web.context.AbstractHttpServletApplicationInitializer
。
这个类负责使用Spring的SessionRepositoryFilter
类(DelegatingFilterProxy
,然后是here和here(注意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时。
值得深思。
希望这可以帮助!
在尝试完建议后,问题仍然存在。现在,我们不再使用ServletContext.addFilter(..)
的单独注册。我们现在使用:
DelegatingProxyFilter
删除了springSessionRepositoryFilter的显式注册。
当我们查看堆栈跟踪时,我们可以看到首先调用此过滤器。因此,过滤器链的顺序似乎完好无损。
我们面临问题的过滤器随后被调用。即使没有提到的变化,这也是相同的行为。
但是,过滤器中的会话对象来自容器。