SpringMVC源码剖析之自动注入Request,为什么可行?

简介: 我们知道在SpringMVC中controller层可以通过Autowire自动注入Request到当前类来使用。如果看过Spring源码,IOC容器进行实例化bean的时候,一级缓存中存放的都是单例Bean。

问题:

我们知道在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放入当前线程中
在这里插入图片描述

总结

在这里插入图片描述

相关文章
|
6月前
|
Java Spring
SpringMVC控制层private方法中出现注入的service对象空指针异常
一、现象 SpringMVC中controller里的private接口中注入的service层的bean为null,而同一个controller中访问修饰符为public和protected的方法不会出现这样的问题。 controller中的方法被AOP进行了代理,普通Controller如果没有AOP,private方法中bean也是正常的。
|
Java
SpringMVC之自动注入Request对象
前几天看了领导写的一段代码,在Controller中注入了HttpServletRequest,形式如下所示: @RestController public class AutowiredRequestController { @Aut...
1530 0
springmvc注入类 NoUniqueBeanDefinitionException: No qualifying bean of type [] is defined: expected single错误
在springmvc中注入服务时用@Service 当有两个实现类时都标明@Service后则会出现异常: nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.james.dao.impl.BaseDao] is defined: expected single matching bean but found 2:  这是因为都标明了@Service会自动注入,这时会导致不清楚实际运行时实例化哪一类。
1712 0
|
Java Spring 应用服务中间件
|
前端开发 Java 容器
【spring源码学习】springMVC之映射,拦截器解析,请求数据注入解析,DispatcherServlet执行过程
【一】springMVC之url和bean映射原理和源码解析 映射基本过程 (1)springMVC配置映射,需要在xml配置文件中配置  (2)配置后,该配置将会交由org.springframework.web.servlet.config.MvcNamespaceHandler处理,该类会转交给org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser做解析。
1703 0
|
前端开发 Java Spring
Spring Mvc 公共Controller 使用拦截器注入请求信息
在Spring Mvc 中我们在Controller 中要想使用 HttpServletRequest HttpSession HttpServletResponse 等请求信息,这些信息有多种方式,这里就重点说下我使用的拦截器注入方式 方式一:(使用注解) /** * 每一个Control 被执行时 * * @author jiangz
3490 0
|
Java 数据格式
springMvc源码学习之:spirngMvc的参数注入的问题
转载:https://my.oschina.net/lichhao/blog/172562 概述在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转 换,底层这种灵活的消息转换机制,就是Spring3.x中新引入的HttpMessageConverter即消息转换器机制。
1131 0
|
Java Spring 容器
配置springmvc在其他类中(spring容器外)获取注入bean
学习https://github.com/thinkgem/jeesite 今天在写JedisUtils的时候要注入JedisPool,而这个属性被设置为static,@Resource和@Autowired都不可以注入,因为spring不能为静态变量依赖注入。
1000 0