前几天看了领导写的一段代码,在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中得到的对象中的值。
来源:CSDN
作者:木叶之荣
链接:https://blog.csdn.net/zknxx/article/details/77917290