使用spring-session-jdbc的Filter之后,会话对象在以后的CompositeFilter中为空

时间:2019-05-08 03:28:25

标签: spring jdbc spring-session

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

  

使用SpringSessionRepositoryFilter后,会话对象在   每个请求开始时OtherFilter的处理时间

我尝试过的事情:

  
      
  • 在Controller和JSP中,OtherFilter之后,会话对象不是空的并且可以正常工作
  •   
  • 在不使用springSessionRepositoryFilter的情况下,会话对象不是空的,并且可以在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。发布
  •   
  • wildfly-11.0.0.Final
  •   
  • Oracle Database 18c Express Edition版本18.0.0.0.0
  •   

2 个答案:

答案 0 :(得分:0)

此问题的原因

  
      
  • @OtherFilter中的@Autowired SessionObj
  •   
  • @OtherFilter之后在控制器中自动连接SessionObj
  •   

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

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的顺序

  

a。在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。在OtherFilter

    通过[requestAttributes]绑定到
  • SessionObj HttpServletRequestImpl的实例(没有来自数据库的会话信息),所以 它是空的
  d。在FrameworkServlet中

  • 对象[requestAttributes]与的实例重新绑定 SessionRepositoryRequestWrapper(带有来自数据库的会话信息)是 包裹在上一个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。在Controller中OtherFilter之后

    通过[requestAttributes]绑定到
  • SessionObj SessionRepositoryRequestWrapper的实例(带有来自 DB),所以效果很好

该问题的一个解决方案

  

在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>
            <!--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);
    } 

答案 1 :(得分:0)

此问题的另一个解决方案

  

在springSessionRepositoryFilter和之间添加requestContextFilter   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>
            <!--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这样 未来)