美文网首页
@Autowired依赖注入HttpServletRequest

@Autowired依赖注入HttpServletRequest

作者: 繁书_ | 来源:发表于2021-08-13 15:20 被阅读0次

    场景

    通常来说依赖注入的对象一旦创建完成后就不会在改变,因为Spring的默认行为创建的都是单例对象。HttpServletRequestHttpServletResponse不是单例对象,它们都是根据HTTP请求进行创建的,一个HTTP请求对象一个request和response。但是通过@Autowired可以实现每当一个请求进来时使用的都是当前的request或response对象,

    演示代码如下

    @RestController
    @RequestMapping("/test")
    public void TestController {
        @Autowired
        private HttpServletRequest request;
        
        @GetMapping("/request")
        public String test() {
            String queryString = request.getQueryString();
        }
    }
    

    实现原理

    实际上,通过@Autowire注入的HttpServletRequest只是一个代理对象,其内部会实时获取当前请求对应的真正的HttpServletRequest对象。

    在上面的TestController中,框架在进行依赖注入HttpServletRequest 时,会去IOC容器中查找类型为HttpServletRequest的Bean,

    首先会调用DefaultListableBeanFactory#doResolveDependency(DependencyDescriptor, String, Set<String>, TypeConverter)进行依赖的解析,最终会调用到DefaultListableBeanFactory#findAutowireCandidates(String, Class<?>, DependencyDescriptor), 该方法主要是从依赖注入源中查找对应类型的Bean,源码如下:

    // 存放用于依赖注入的Bean
    private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
    
    protected Map<String, Object> findAutowireCandidates(
                @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
    
            String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this, requiredType, true, descriptor.isEager());
            Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
            for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
                if (autowiringType.isAssignableFrom(requiredType)) {
                    // 从依赖注入源查找对应类型的Bean
                    Object autowiringValue = this.resolvableDependencies.get(autowiringType);
                    
                    // 如果有必要的话,为autowiringValue创建代理对象
                    autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
                    if (requiredType.isInstance(autowiringValue)) {
                        result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                        break;
                    }
                }
            }
        
        // 省略其他代码...
        return result;
    }
    

    值得注意的是resolvableDependencies中存放的Bean只用于依赖注入,不用于依赖查找

    this.resolvableDependencies.get(autowiringType);这段代码中会获取到一个类型为RequestObjectFactory的Bean,该Bean实现了ObjectFactory 接口,属于WebApplicationContextUtils的内部类,源码如下

        private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {
    
            @Override
            public ServletRequest getObject() {
                return currentRequestAttributes().getRequest();
            }
    
            @Override
            public String toString() {
                return "Current HttpServletRequest";
            }
        }
    
    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;
    }
    

    通过代码可以看出来RequestObjectFactory 的作用就是实时从ThreadLocal中获取当前请求对应的request对象,RequestContextHolder 内部使用的就是ThreadLocal

    在获取到RequestObjectFactory 对象后,AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType) 这段代码中会为其创建一个代理对象,源码如下

    // AutowireUtils#resolveAutowiringValue
    public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
            if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
                // 此时 factory = RequestObjectFactory
                ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
                if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
                    
                    // 创建代理对象, requiredType = HttpServletRequest.class
                    // 并将RequestObjectFactory传入ObjectFactoryDelegatingInvocationHandler中
                    autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
                            new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
                }
                else {
                    return factory.getObject();
                }
            }
            return autowiringValue;
        }
    
    
    private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
    
            private final ObjectFactory<?> objectFactory;
    
            public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
                this.objectFactory = objectFactory;
            }
    
            @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();
                }
                
                // 在代理类中,每次调用HttpServetRequest中的方法都会去RequestObjectFactory中获取线程本            // 地变量中的HttpServletRequest对象,并通过反射调用其对应的方法
                try {
                    return method.invoke(this.objectFactory.getObject(), args);
                }
                catch (InvocationTargetException ex) {
                    throw ex.getTargetException();
                }
            }
    

    从源码中可以看出在示例代码TestController中调用request.getQueryString(),会直接进入到ObjectFactoryDelegatingInvocationHandlerinvoke()方法中,然后通过反射的方式调用真正的HttpServletRequest对象中的方法

    RequestObjectFactory 和 RequestAttributes 初始化时机

    RequestObjectFactory

    在容器启动阶段,会有一个BeanFactory后置处理阶段,其中会调用AbstractApplicatioContext#postProcessBeanFactory(ConfigurableListableBeanFactory) 方法,其中一个子类,AnnotationConfigReactiveWebServerApplicationContext对其进行了实现,其中会调用到WebApplicationContextUtils#registerWebApplicationScopes(ConfigurableListableBeanFactory, ServletContext)方法,源码如下

    public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
                @Nullable ServletContext sc) {
    
            beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
            beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
            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);
            }
    
            // 添加依赖注入Bean的来源
            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);
            }
    }
    
    // DefaultListableBeanFactory#registerResolvableDependency
    public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
            Assert.notNull(dependencyType, "Dependency type must not be null");
            if (autowiredValue != null) {
                if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
                    throw new IllegalArgumentException("Value [" + autowiredValue +
                            "] does not implement specified dependency type [" + dependencyType.getName() + "]");
                }
                // 添加进依赖注入源
                this.resolvableDependencies.put(dependencyType, autowiredValue);
            }
    }
    

    在上面代码中会将RequestObjectFactory和其他实现了ObjectFactory接口的对象添加到依赖注入源中,到这一步也就和上面获取requset对象的过程对应起来了

    RequestAttributes

    RequestAttributes 在Spring中的多处代码中都有使用到,这里列举两个Web场景下常用的两处

    RequestContextFilter中

    第一个在过滤器RequestContextFilter中,会把当前的HttpServletRequestHttpServletResponse都放入ThreadLocal中,过滤器代码如下

    public class RequestContextFilter extends OncePerRequestFilter {
        
        // 省略类中其他代码...
        
        // 该方法属于OncePerRequestFilter的模板方法,
        // 会在OncePerRequestFilter#doFilter(ServletRequest, ServletResponse, FilterChain)中被调用
        protected void doFilterInternal(
                HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
    
            // 创建RequestAttributes的子类对象`ServletRequestAttributes`
            ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
            // 初始化RequestContextHolder
            initContextHolders(request, attributes);
    
            try {
                filterChain.doFilter(request, response);
            }
            finally {
                resetContextHolders();
                if (logger.isDebugEnabled()) {
                    logger.debug("Cleared thread-bound request context: " + request);
                }
                attributes.requestCompleted();
            }
        }
        
        
        private void initContextHolders(HttpServletRequest request, ServletRequestAttributes requestAttributes) {
            LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
            // 将RequestAttributes 放入ThreadLocal中
            RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
        }
        
    }
    

    RequestContextListener中

    RequestContextListener 实现了Servlet中的监听器ServletRequestListener, 当事件发生,会将requset对象放入ThreadLocal

    public class RequestContextListener implements ServletRequestListener {
    
        private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
                RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
    
    
        @Override
        public void requestInitialized(ServletRequestEvent requestEvent) {
            if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
                throw new IllegalArgumentException(
                        "Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
            }
            HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
            ServletRequestAttributes attributes = new ServletRequestAttributes(request);
            request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
            LocaleContextHolder.setLocale(request.getLocale());
            RequestContextHolder.setRequestAttributes(attributes);
        }
    }
    

    相关文章

      网友评论

          本文标题:@Autowired依赖注入HttpServletRequest

          本文链接:https://www.haomeiwen.com/subject/feodbltx.html