spring-session源码解读2

来源:互联网 发布:上瘾 顾海 知乎 编辑:程序博客网 时间:2024/05/16 18:11

摘要: ServletRequestWrapper Servlet规范从2.3起引入了ServletRequestWrapper包装类,它把调用交给被包装的ServletRequest来执行。这样就可以对ServletRequest进行扩展。例如Tomcat就是将自己的Request类作为包装类的实体。 public class ServletRequestWrapper i

ServletRequestWrapper

Servlet规范从2.3起引入了ServletRequestWrapper包装类,它把调用交给被包装的ServletRequest来执行。这样就可以对ServletRequest进行扩展。例如Tomcat就是将自己的Request类作为包装类的实体。

public class ServletRequestWrapper implements ServletRequest {    private ServletRequest request;    public ServletRequestWrapper(ServletRequest request) {        if (request == null) {            throw new IllegalArgumentException("Request cannot be null");           }        this.request = request;    }    public ServletRequest getRequest() {        return this.request;    }    public Object getAttribute(String name) {        return this.request.getAttribute(name);    }}

为了更好的支持HttpServletRequest,Servlet2.3还支持了提供了HttpServletRequestWrapper,其实现了接口HttpServletRequest,并且继承了ServletRequestWrapper。

public class HttpServletRequestWrapper extends ServletRequestWrapper implements        HttpServletRequest {    public HttpServletRequestWrapper(HttpServletRequest request) {        super(request);    }    private HttpServletRequest _getHttpServletRequest() {        return (HttpServletRequest) super.getRequest();    }//省略}   

spring request wrapper

spring request类图
SessionRepositoryRequestWrapper继承了HttpServletWrapper,并覆盖了getSession方法,通过spring自己的策略生成session。此外提供了commitSession方法来进行session提交时处理,下一章会专门讲session生命周期。

spirng response wrapper

spirng response类图
1. spring定义了新的response wrapper–OnCommittedResponseWrapper,其关联了自实现的字符和字节输出流,并定义了一个模板方法onResponseCommitted,由继承子类来实现。 
2. OnCommittedResponseWrapper关联了自己实现的一个字节流和字符流。他们和普通的字节字符流一样也是个包装类。

通过SessionRepositoryFilter对Servlet侵入

spring-session通过Filter将自定义的Request wrapper和Response Wrapper侵入到Servlet容器中。

在Tomcat中Servlet的service方法会由ApplicationFilterChain调用,而FilterChain的参数通过Filter的filterChain.doFilter传入。Spring-session通过自定义的全局拦截器SessionRepositoryFilter(详见第一篇)将request和response侵入进容器。

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {        request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);        SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, servletContext);        SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);        HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);        HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);        try {            filterChain.doFilter(strategyRequest, strategyResponse);        } finally {            wrappedRequest.commitSession();        }    }

SessionRepositoryFilter继承了OncePerRequestFilter,父类的doFilter最终会将具体的处理逻辑交给子类处理。

abstract class OncePerRequestFilter implements Filter {    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)            throws ServletException, IOException {//alreadyFilteredAttributeName是个静态变量,由类名+.filtered构成//这样就能保证同一个类只被调用一次。        boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;        if (hasAlreadyFilteredAttribute) {            filterChain.doFilter(request, response);        }        else {            request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);            try {            //通过模板方法,将处理交给子类                doFilterInternal(httpRequest, httpResponse, filterChain);            }        }    }}

OncePerRequestFilter是用来保证一次完整的拦截链中,同一个类只会被调用一次。 
因为spring无法保证同一个Filter类只有一个实例。有可能一个Filter既有可能在web.xml里配置由容器初始化了,还有可能被作为spring的依赖引入进了DelegatingFilterProxy。这样在一次filter chain中就会存在同一个Filter的多个实例。

原创粉丝点击