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的多个实例。
相关文章推荐
- tiles3 基础使用及与spring mvc集成
- SpringMVC 拦截器(不过滤某个路径)
- java中将json转换成map
- Struts2.properties属性文件中的devModel和DynamicMethodInvocation。。。Action中servlet对象的获取
- Struts2中使用Servlet API步骤
- java设计模式(五)—命令模式
- Ant之Task
- Java的一些小知识:package,import,不同目录下类的调用
- Java动态代理原理
- 三个例子讲清楚Java反射
- Java线程2-4 单任务线程池SingleThreadPool
- java并发--队列同步器原理一
- 第三个spring冲刺第4天
- java多线程模拟聊天问题
- JAVA面向对象
- Java线程2-3 时间调度的线程池ScheduledThreadPool
- Struts2框架学习之三:result返回结果
- Spring配置文件所有类型的数据源dataSource
- java web 答辩总结
- java.lang.IndexOutOfBoundsException 错误解决