【问题标题】:After using Filter of spring-session-jdbc session object is empty in later CompositeFilter使用 Spring-session-jdbc 的 Filter 后,会话对象在后面的 CompositeFilter 中为空
【发布时间】:2019-05-08 03:28:24
【问题描述】:

问题描述(似乎是时间问题):

使用SpringSessionRepositoryFilter后,会话对象为空 每个请求开始时OtherFilter的处理周期

我尝试过的:

  • 在OtherFilter之后的Controller和JSP中,session对象不为空,工作正常
  • 不使用springSessionRepositoryFilter,session对象是notempty,在OtherFilter中可以正常工作

配置如下:

<bean class="org.springframework.web.filter.CompositeFilter" name="springChainFilter">
    <property name="filters">
        <list>
            <bean id="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
            </bean>

            <!--Other Later Filter -->
            <bean id="otherFilter" class="xxx.xxx.OtherFilter">
            </bean>
        </list>
    </property>
</bean>

<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration"/>

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <constructor-arg ref="dataSource"/>
</bean>

<bean id="cookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
    <property name="cookieName" value="JSESSIONID" />
</bean>

OtherFilter 定义如下:

public class OtherFilter extends OncePerRequestFilter {


    @Autowired
    private SessionObj sessionObj;

    ......
}

会话对象定义如下:

@Component
@SessionScope
public class SessionObj implements Serializable {

    private static final long serialVersionUID = 1L;


    private String xxId;

    ......
}

环境版本信息:

  • spring-session-jdbc-2.1.5.RELEASE
  • wildfly-11.0.0.Final
  • Oracle Database 18c Express Edition Release 18.0.0.0.0

【问题讨论】:

    标签: spring jdbc spring-session


    【解决方案1】:

    此问题的另一种解决方案

    在 springSessionRepositoryFilter 和 其他过滤器

    <bean class="org.springframework.web.filter.CompositeFilter" name="springChainFilter">
        <property name="filters">
            <list>
                <bean id="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
                </bean>
                <!--Request Context Filter -->
                <bean id="requestContextFilter" class="org.springframework.web.filter.RequestContextFilter" />
                <!--Other Later Filter -->
                <bean id="otherFilter" class="xxx.xxx.OtherFilter">
                </bean>
            </list>
        </property>
    </bean>
    

    在RequestContextFilter中(spring框架应用)

    • wrappedRequest 暴露给当前线程,通过两者 LocaleContextHolder 和 RequestContextHolder
    • [requestAttributes] 与一个实例绑定 SessionRepositoryRequestWrapper(像 FrameworkSevlet 那样做 未来)

    【讨论】:

      【解决方案2】:

      这个问题的原因

      • OtherFilter 中的@Autowired SessionObj
      • @Autowired SessionObj 在控制器后 OtherFilter

      以上两种情况,DI源都是绑定到[requestAttributes]对象的request#getsession()。

      org.springframework.web.context.request.ServletRequestAttributes
      
          protected final HttpSession getSession(boolean allowCreate) {
              if (isRequestActive()) {
                  HttpSession session = this.request.getSession(allowCreate);
                  this.session = session;
                  return session;
              }
          }
      

      在一个请求期间有以下里程碑:

      a 到 e 的序列

      一个。在 RequestContextListner 中

      • 对象 [requestAttributes] 与一个实例绑定 HttpServletRequestImpl(没有来自数据库的会话信息)

        org.springframework.web.context.request.RequestContextListener

        public void requestInitialized(ServletRequestEvent requestEvent) {
            if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
                throw new IllegalArgumentException(
                        "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
            }
            HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
            ServletRequestAttributes attributes = new ServletRequestAttributes(request);
            request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
            LocaleContextHolder.setLocale(request.getLocale());
            RequestContextHolder.setRequestAttributes(attributes);
        }
        

      b.在 SessionRepositoryFilter

      • 请求用 SessionRepositoryRequestWrapper 包装(带会话 来自数据库的信息)
      • 但是,对象 [requestAttributes] 没有重新绑定 带有 SessionRepositoryRequestWrapper 的实例

        org.springframework.session.web.http.SessionRepositoryFilter

        protected void doFilterInternal(HttpServletRequest request,
                HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
        
            SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
                    request, response);
            SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
                    wrappedRequest, response);
        
            try {
                filterChain.doFilter(wrappedRequest, wrappedResponse);
            }
        }
        

      c。在其他过滤器中

      • SessionObj 通过 [requestAttributes] 注入 HttpServletRequestImpl 的实例(没有来自 DB 的会话信息),所以 是空的

      d。在 FrameworkServlet 中

      • 对象 [requestAttributes] 与一个实例重新绑定 SessionRepositoryRequestWrapper(带有来自 DB 的会话信息) 包裹在前面的b过程中

        org.springframework.web.servlet.FrameworkServlet

        protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
        
            ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
            initContextHolders(request, localeContext, requestAttributes);
            }
        
        private void initContextHolders(HttpServletRequest request,
                @Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
        
            if (requestAttributes != null) {
                RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
            }
        
        }
        

      e。在其他过滤器之后的控制器中

      • SessionObj 通过 [requestAttributes] 注入 SessionRepositoryRequestWrapper 的实例(带有来自的会话信息 DB),所以它工作正常

      这个问题的一个解决方案

      在 springSessionRepositoryFilter 之间添加一个 Session Retrieve Filter 和其他过滤器

      <bean class="org.springframework.web.filter.CompositeFilter" name="springChainFilter">
          <property name="filters">
              <list>
                  <bean id="springSessionRepositoryFilter" class="org.springframework.session.web.http.SessionRepositoryFilter">
                  </bean>
                  <!--Session Retrieve Filter -->
                  <bean id="sessionRetrieveFilter" class="xxx.xxx.SessionRetrieveFilter">
                  <!--Other Later Filter -->
                  <bean id="otherFilter" class="xxx.xxx.OtherFilter">
                  </bean>
              </list>
          </property>
      </bean>
      

      在会话检索过滤器中,将 [requestAttributes] 与 SessionRepositoryRequestWrapper 的实例(做类似的事情 FrameworkSevlet 以后做)

      xxx.xxx.SessionRetrieveFilter
      
          protected void doFilterInternal(HttpServletRequest request,
                  HttpServletResponse response, FilterChain filterChain)
                  throws ServletException, IOException {
      
              RequestAttributes wrappedAttributes = new ServletRequestAttributes(request, response);
              RequestContextHolder.setRequestAttributes(wrappedAttributes);
      
              filterChain.doFilter(request, response);
          } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-14
        • 2019-05-30
        • 2020-03-28
        • 2014-05-02
        • 2013-04-30
        • 1970-01-01
        相关资源
        最近更新 更多