转载自:http://www.see-source.com/ 源码解析网 java
接着上一篇继续,源码以下: session
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; ServletContext servletContext = getServletContext(); String timerKey = "FilterDispatcher_doFilter: "; try { // FIXME: this should be refactored better to not duplicate work with the action invocation ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); ActionContext ctx = new ActionContext(stack.getContext()); ActionContext.setContext(ctx); UtilTimerStack.push(timerKey); request = prepareDispatcherAndWrapRequest(request, response); ActionMapping mapping; try { mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager()); } catch (Exception ex) { log.error("error getting ActionMapping", ex); dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); return; } if (mapping == null) { // there is no action in this request, should we look for a static resource? String resourcePath = RequestUtils.getServletPath(request); if ("".equals(resourcePath) && null != request.getPathInfo()) { resourcePath = request.getPathInfo(); } if (staticResourceLoader.canHandle(resourcePath)) { staticResourceLoader.findStaticResource(resourcePath, request, response); } else { // this is a normal request, let it pass through chain.doFilter(request, response); } // The framework did its job here return; } dispatcher.serviceAction(request, response, servletContext, mapping); } finally { try { ActionContextCleanUp.cleanUp(req); } finally { UtilTimerStack.pop(timerKey); } } }生成一个ActionContext实例,并用值栈的上下文 stack.getContext() 做为构造参数传入。 ActionContext顾名思义,是个action的上下文环境,能够想到它的生命周期也应该跟action有关,即伴随着action的建立而建立,action的销毁而销毁。能够这么说,但不许确,仍是经过代码准确地分析下,进入 ActionContext定义 :
public class ActionContext implements Serializable { static ThreadLocal actionContext = new ThreadLocal(); Map<String, Object> context; public ActionContext(Map<String, Object> context) { this.context = context; } public static void setContext(ActionContext context) { actionContext.set(context); } public static ActionContext getContext() { return (ActionContext) actionContext.get(); } public void setSession(Map<String, Object> session) { put(SESSION, session); } public Map<String, Object> getSession() { return (Map<String, Object>) get(SESSION); } public void setValueStack(ValueStack stack) { put(VALUE_STACK, stack); } public ValueStack getValueStack() { return (ValueStack) get(VALUE_STACK); } public Object get(String key) { return context.get(key); } public void put(String key, Object value) { context.put(key, value); } . . . //省略 }属性context用于存放ValueStack的上下文,其值是经过构造方法传入的。仔细看下上面的定义代码发现,方法虽然定义的很多,但都是形如getXXX()、setXXX()的方法,而且最终都是访问context的,因此能够总结出ActionContext的做用实际上只是提供了访问context的操做,而Action的上下文实际上也就是context,Action上下文的建立时间也就是 ValueStack建立时间。
静态属性actionContext是java.lang.ThreadLocal类型,通常讲是thread的局部变量。经过ThreadLocal的set()方法能够将值存储到当前线程的局部变量中,经过get()方法能够获取(访问)当前线程局部变量的值。在ActionContext内部,经过静态方法setContext()将上下文存入当前线程的局部变量中,这样在整个线程生命周期均可经过静态方法getContext()进行访问。在doFilter()方法中能够看到,生成ActionContext实例后,立刻就经过setContext()将上下文存入当前线程的局部变量中。 app
为了上更好的理解上下文的生命周期,下面将ThreadLocal类进行简单的分析下: this
public class Thread implements Runnable { ThreadLocal.ThreadLocalMap threadLocals = null; . . . //省略 }
这个是线程Thread的定义源码,其中有个属性threadLocals,是ThreadLocal.ThreadLocalMap类型,是ThreadLocal定义的一个内部类ThreadLocalMap.这个属性才是真正充当每一个线程局部变量的,而ThreadLocal只是用来管理全部线程局部变量的。ThreadLocalMap顾名思义,是个Map,但它并不是实现了Map接口,只是实现了至关于Map的功能。看下ThreadLocal定义源码: spa
public class ThreadLocal<T> { public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } protected T initialValue() { return null; } . . . //省略 }1.先看set()方法。利用Thread.currentThread()返回当前线程,而后以当前线程为参数调用getMap()返回当前线程的局部变量(Thread的threadLocals属性)。if (map != null)局部变量存在,经过map.set(this, value)将值存入。this是当前的ThreadLocal实例,value是存入局部变量的值。能够看到ThreadLocal这里是做为了map的key值,这样不一样的ThreadLocal实例得到的值是不一样的,这样就是为何通常 ThreadLocal都会定义成静态的。 因此从这个角度能够理解为:每一个ThreadLocal都是当前线程 的一个局部变量。另外,若是局部变量不存在时,经过createMap()方法为当前线程建立个 ThreadLocal.ThreadLocalMap实例,并赋值给当前线程的 threadLocals属性。
2.get()方法其实就是set的逆过程,就不说了。但其中的setInitialValue()方法看下,它的做用是初始化局部变量,当当前线程的局部变量存在时,将当前的ThreadLocal下的值置null,initialValue()方法只是返回个null;当当前线程的局部变量不存在时,建立个,并将当前的ThreadLocal下的值置null。 线程
其实,在早期的jdk版本中ThreadLocal并不是是这样实现,Thread中并无threadLocals属性,而是经过在ThreadLocal中维护一个Map,Map的key值就是当前线程,value值就是咱们要存入的值。 code