您的位置:首页 > 编程语言 > Java开发

spring-session源码解读-3

2015-12-11 00:00 387 查看

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



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

spirng response wrapper



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的多个实例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: