问题:
我们知道在SpringMVC中controller层能够经过Autowire自动注入Request到当时类来使用 如果看过Spring源码,IOC容器进行实例化bean的时分,一级缓存中寄存的都是单例Bean。
那么是否意味着Request,也是单例Bean,会不会出现线程安全?
如果使用过request,发现其并不会出现线程安全问题,那为什么单例Bean Request不会出现线程安全问题?
解决概述
request实际上是一个署理目标,因此依靠注入request是一个署理目标,当经过request.getXXX() 的时分,实际上走到了署理类的invoke办法上,而invoke办法本质上是经过method.invoke进行反射调用,需要一个实在的目标目标。
目标目标的获取是从RequestContextHolder中获取的,当时恳求进来的时分,正经过过滤器filter,RequestContextHolder经过threadLocal将current request进行存储到当时线程,反射调用的时分获取从当时线程。
预备
1、先从依靠注入视点来看,能够看到注入给userController的是一个署理目标,经过jdk proxy进行署理的request目标注入到了userController中(依靠注入交由AutowireAnnotationBeanPostProcessor处理)
经过AutowireAnnotationBeanPostProcessor实现依靠注入 获取候选的Bean进行注入 jdk proxy 创立署理目标,并指定了invocationHandler(调度处理器)
特点赋值依靠注入之后,能够看到userController中注入了署理目标request
2、调用目标handler办法的时分,署理目标request,经过invoke进行调用。终究经过method.invoke 进行反射调用。调用需要实在request目标,实在的request目标,从RequestContextHolder获取,RequestContextHolder经过ThreadLocal从当时线程中获取,而Thread中的变量属于当时线程所有,是线程安全的
requestAttributesHolder 是一个TheadLocal
3、RequestContextHolder 什么时分将 恳求request经过ThreadLocal 放入当时线程中的。能够看到当恳求经过 OncePerRequestFilter的时分,寄存request进当时线程
public class RequestContextFilter extends OncePerRequestFilter {
/**
* Returns "false" so that the filter may set up the request context in an
* error dispatch.
*/
@Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
// 过滤器filter
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
// 初始化contextHolder
initContextHolders(request, attributes);
try {
filterChain.doFilter(request, response);
}
finally {
resetContextHolders();
if (logger.isTraceEnabled()) {
logger.trace("Cleared thread-bound request context: " + request);
}
attributes.requestCompleted();
}
}
private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
// RequestContextHolder 设置 RequestAttributes
RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
if (logger.isTraceEnabled()) {
logger.trace("Bound request context to thread: " + request);
}
}
RequestContextHolder经过ThreadLocal 将request放入当时线程中
总结