java - 在 Servlet 过滤器中调用容器的会话对象而不是 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 过滤器中调用它最终会得到容器创建的会话对象。
任何帮助深表感谢。
根据@John Blum 的评论进行了重新设计,但仍然面临同样的问题。
解决方案
简而言之,为了让Spring Session,特别是Spring Session for Pivotal GemFire (SSDG) 完成其工作,在向 (Web) 注册时, SessionRepositoryFilter
( Javadoc , Source ) 必须是过滤器链中的第一个Servlet 过滤器应用程序容器(例如 Apache Tomcat、Eclipse Jetty 等)。
否则,如果Spring Session SessionRepositoryFilter
不是过滤器链中的第一个 Servlet 过滤器,那么Spring Session将不会(尚未)拦截 HTTP 请求并且将无法行使替换 Container 会话的机会(通过包装HttpServletRequest
with SessionRepositoryFilter.SessionRepositoryRequestWrapper
,请参阅此处)与Spring SessionSession
提供的使用适当的提供程序(例如,使用 SSDG 的 GemFire),由在(此处)上设置的实现确定。SessionRepository
SessionRepositoryFilter
您的 Spring Web MVC 应用程序Controller
工作的原因是,Java EE Servlet Spec/Container 保证在使用 HTTP 请求(即)调用任何 Servlet 之前调用所有 Servlet 过滤器HttpServletRequest
。而且,由于 Spring Web MVCDispatcherServlet
是适当的HttpServlet
并且负责调用您的应用程序定义的 Spring Web MVC Controllers
,因此Controllers
保证应用程序可以看到“替换”的 HTTP 请求(以及扩展的 HTTP 会话对象)。
所以,一些家务用品......我不(完全)确定你的意思是:
2.0.5
宝石火的版本。2.0.5
指Pivotal GemFire 的最新/当前版本的 Spring Session。和
webappinitializer
?
对于#2,您的意思是您专门创建了一个 SpringWebApplicationInitializer
来手动显式注册SessionRepositoryFilter
, (如代码片段中所示)?
你知道Spring Session已经提供了这样一个类吗o.s.session.web.context.AbstractHttpServletApplicationInitializer
......
这个类负责注册SessionRepositoryFilter
使用 Spring 的DelegatingFilterProxy
类(这里,然后这里,和这里(注意insertBeforeOtherFilters
实例变量,默认为true
),并且以正确的顺序,这里,嗯,特别是这里)。
有趣的是,您在上面的过滤器注册代码片段中似乎正在做相同或相似的事情。
注意:这(Servlet 容器的编程配置)仅适用于 Servlet 3.0 容器及更高版本。
您可以看到Spring Session 是 AbstractHttpServletApplicationInitializer
如何在示例中使用的,例如,here。有关该示例的更多详细信息,请参见示例Initializer
的相应指南文档。
我注意到您的 SpringDelegatingFilterProxy
类注册(以bean 命名,命名为“springSessionRepositoryFilter”)的不同之处在于,您将作为第二个参数传递给,如下所示...SessionRepositoryFilter
DelegatingFilterProxy.class
servletContext.addFilter("filterName", <FilterType>);
FilterRegistration.Dynamic springSessionRepositoryFilter =
container.addFilter("springSessionRepositoryFilter", DelegatingFilterProxy.class);
但是,Spring Session(核心)本身实际上构造和初始化(使用“springSessionRepositoryFilter”bean 名称)SpringDelegatingFilterProxy
类的实例,并将该“实例”传递给ServletContext.addFilter(..)
注册时的方法(第二个参数)。
我怀疑API 本身在构造/初始化实例时ServletContext.addFilter(..)
仅使用 Spring 类的默认构造函数,这可能是您问题的根源,尤其是在以编程方式注册 Servlet 过滤器时。DelegatingProxyFilter
深思熟虑。
希望这可以帮助!
推荐阅读
- javascript - JavaScript - 查找所有具有类的元素,查找重复项并显示它们
- asp.net-core - 在 asp.net core 3 中渲染 rdl
- python - 如何在 Keras/TensorFlow 中可视化 RNN/LSTM 权重?
- php - Laravel 从 5.6 迁移到 5.8,现在所有 url 链接都不起作用
- c++ - 如何将 glfw 库包含到 C++ 项目中?
- mysql - MYSQL中按时间段链接的事实与时间维度表
- c++ - Is there a way to expand and call a tuple of std::functions?
- javascript - 如何判断 ES6 类是否具有给定名称的 getter?
- sql - ORACLE SQL - 我如何计算,但选择的属性比我想要分组的多?
- python - 在对象数组中查找唯一值并附加所有相关值