前几天看了领导写的一段代码,在Controller中注入了HttpServletRequest,形式如下所示:
@RestController public class AutowiredRequestController { @Autowired private HttpServletRequest request; }当时看到了这一段代码,首先想到的是AutowiredRequestController是一个singleton的bean,HttpServletRequest是一个变化的共享变量,每个请求对象都是不一样的,这样写不会有线程安全问题吗?带着疑问去翻了翻SpringMVC的源码,结论是:不会有线程安全问题!!!不会有线程安全问题!!!!不会有线程安全问题!!!下面我们来分析一下:
在前面的文章中我们简单的分析过SpringMVC的上下文初始化过程(SpringMVC之浅析上下文初始化(一)和 SpringMVC之浅析上下文初始化(二)),SpringMVC环境中的父上下文时:XmlWebApplicationContext。下面我们先看一下XmlWebApplicationContext的UML类图(去掉了一些暂时无关的):
之前也说过会调用AbstractApplicationContext中的refresh方法进行Bean的组装初始化的过程,在refresh()这个方法中会调用:postProcessBeanFactory()这个方法,设置一些需要预先处理的Bean。而XmlWebApplicationContext继承了AbstractRefreshableWebApplicationContext,AbstractRefreshableWebApplicationContext中重写了postProcessBeanFactory这个方法,我们去AbstractRefreshableWebApplicationContext这个类中看一下这个方法的内容:
@Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //注册Bean的生命周期的相关的类(实现了BeanPostProcessor接口) beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); //需要忽略依赖检查的接口 beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); //这个是这次要重点分析的类 WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); //注册一些环境变量相关的类 WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); }WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);这个方法是我们需要重点分析的类,我进去看一下:
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) { beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false)); beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true)); if (sc != null) { ServletContextScope appScope = new ServletContextScope(sc); beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); // Register as ServletContext attribute, for ContextCleanupListener to detect it. sc.setAttribute(ServletContextScope.class.getName(), appScope); } beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory()); beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory()); beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory()); beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory()); if (jsfPresent) { FacesDependencyRegistrar.registerFacesDependencies(beanFactory); } }在这个类中注册了Web开发相关的三个Scope:RequestScope、SessionScope和全局的SessionScope以及一个ServletContextScope。接下来了注册了几个实现了ObjectFactory的Bean。RequestObjectFactory、RequestObjectFactory、SessionObjectFactory、WebRequestObjectFactory。这几个类是在Controller中注入Request和Response的关键。我们先记住 RequestObjectFactory这个类。这几个类被放到了resolvableDependencies中。resolvableDependencies这个Map中存放的是在Autowire时所要使用到的bean的类型和对应的Object。
下面我们去看一下在Controller中注入Request的一个过程。首先看一下相应的一些调用链:
这个调用链比较长,调用链的执行过程也很复杂,这里先不过多展开的,我们直接进入到关键代码中。先进入到DefaultListableBeanFactory的findAutowireCandidates这个方法中,看一些关键代码:
protected Map<String, Object> findAutowireCandidates( String beanName, Class<?> requiredType, DependencyDescriptor descriptor) { String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this, requiredType, true, descriptor.isEager()); Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length); for (Class<?> autowiringType : this.resolvableDependencies.keySet()) { if (autowiringType.isAssignableFrom(requiredType)) { Object autowiringValue = this.resolvableDependencies.get(autowiringType); autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType); if (requiredType.isInstance(autowiringValue)) { result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue); break; } } } //省略其他代码 ........... }在上面的代码中我们看到了resolvableDependencies这个属性。当注入HttpServletRequest的时候,requiredType值是HttpServletRequest.class,我们还记得在resolvableDependencies中放入了ServletRequest.class这个key。所以 if (autowiringType.isAssignableFrom(requiredType)) 这个判断会返回true,接着会取得RequestObjectFactory这个对象。接着会调用AutowireUtils.resolveAutowiringValue这个方法进一步的解析Autowire的值。我们进到这个方法中进行看一下:
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) { if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) { ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue; if (autowiringValue instanceof Serializable && requiredType.isInterface()) { autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(), new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory)); } else { return factory.getObject(); } } return autowiringValue; }在这个方法中会先判断上一步取得的autowireValue是不是可以实例化为ObjectFactory 对象。上一步取得的autowireValue是RequestObjectFactory。我们看一下RequestObjectFactory这个类的内容:
private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable { @Override public ServletRequest getObject() { return currentRequestAttributes().getRequest(); } @Override public String toString() { return "Current HttpServletRequest"; } }很明显的实现了ObjectFactory这个接口。接着RequestObjectFactory 是不能实例化为HttpServletRequest对象的。所以会进入到循环体中。接着进一步的判断上一步取得的autowireValue的值能不能被序列化,以及requiredType是不是可以接口,从上面的分析可以看出这个条件也是成立的。所以最终生成的autowireValue的值是一个 JDK动态代理生成的对象。InvocationHandler的实现类为:ObjectFactoryDelegatingInvocationHandler。所以我们在Controller层中所注入的HttpServletRequest其实是一个JDK动态代理生成的对象。这个是很关键的一个 点!!!当我们在Controller中调用的时候:
@RequestMapping("testAutowiredRequest") public String testAutowiredRequest() { request.getParameter("userNmae"); return "success"; }会进入到ObjectFactoryDelegatingInvocationHandler的invoke方法中。我们去看一下:
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("equals")) { // Only consider equal when proxies are identical. return (proxy == args[0]); } else if (methodName.equals("hashCode")) { // Use hashCode of proxy. return System.identityHashCode(proxy); } else if (methodName.equals("toString")) { return this.objectFactory.toString(); } try { return method.invoke(this.objectFactory.getObject(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } }这里对equals方法、hashcode方法、toString方法进行了特殊处理。其他的方法则是直接执行method.invoke的方法。第一个参数为所调用的对象。是通过调用this.objectFactory.getObject()来获取的。objectFactory,通过我们上面的分析我们知道它是RequestObjectFactory这个对象。所以我们去RequestObjectFactory这个类中看一下objectFactory这个方法:
@Override public ServletRequest getObject() { return currentRequestAttributes().getRequest(); }在上面的代码中调用了currentRequestAttributes().getRequest()。我们接着去currentRequestAttributes()这个方法中看一下:
private static ServletRequestAttributes currentRequestAttributes() { RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes(); if (!(requestAttr instanceof ServletRequestAttributes)) { throw new IllegalStateException("Current request is not a servlet request"); } return (ServletRequestAttributes) requestAttr; }看到这里时,你是不是会有一种恍然大悟的感觉呢?((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();这种方式不也是我们经常在代码中获取HttpServletRequest对象的方式吗?我在进一步的分析一下。看一下RequestContextHolder.currentRequestAttributes()这个方法:
public static RequestAttributes currentRequestAttributes() throws IllegalStateException { RequestAttributes attributes = getRequestAttributes(); if (attributes == null) { if (jsfPresent) { attributes = FacesRequestAttributesFactory.getFacesRequestAttributes(); } if (attributes == null) { throw new IllegalStateException(""); } } return attributes; }通过getRequestAttributes()这个方法来获取RequestAttributes对象。我们进入到getRequestAttributes()这个方法中继续看一下:
public static RequestAttributes getRequestAttributes() { RequestAttributes attributes = requestAttributesHolder.get(); if (attributes == null) { attributes = inheritableRequestAttributesHolder.get(); } return attributes; }发现是通过requestAttributesHolder或者inheritableRequestAttributesHolder的get()方法,来获取的RequestAttributes对象。那么requestAttributesHolder和inheritableRequestAttributesHolder是什么呢?
private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal<RequestAttributes>("Request attributes"); private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal<RequestAttributes>("Request context");两个 ThreadLocal的对象!!!到这里总算是一切都真相大白了!!!每次都是从ThreadLocal对象中取的值,那还能不是线程安全的吗?这里在多说一句,什么时候往这两个ThreadLocal中放入值的呢?请接着往下看:org.springframework.web.servlet.FrameworkServlet#processRequest这个方法中有这样的几行代码:
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);//创建ServletRequestAttributes initContextHolders(request, localeContext, requestAttributes);//往ThreadLocal中放入值initContextHolders这个方法的代码如下:
private void initContextHolders( HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) { if (localeContext != null) { LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable); } //把RequestAttributes放入到ThreadLocal中 if (requestAttributes != null) { RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); } }
RequestContextHolder.setRequestAttributes这个方法的内容如下:
public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) { if (attributes == null) { resetRequestAttributes(); } else { if (inheritable) { inheritableRequestAttributesHolder.set(attributes); requestAttributesHolder.remove(); } else { requestAttributesHolder.set(attributes); inheritableRequestAttributesHolder.remove(); } } }不需要再多说了。
这里总结一下:Controller层中所注入的HttpServletReuqest的实现类为JDK动态代理生成的一个代理类,从Request中获取值的时候是从ThreadLocal中得到的对象中的值。