Spring中ObjectFactory的使用以及与FactoryBean 的区别&ServletRequest、ServlertResponse对象注入方式

  在研究ServletRequest 以及 ServletResponse 等注入的过程中,发现还有一个ObjectFactory 对象,简单研究下其使用以及原理。

1. ObjectFactory使用

  下面从两种方式研究其使用, 一种是接口, 一种是类。

1. 主要代码

(1) 类的方式

package cn.xm.controller.system;

public class MyBean {

    public MyBean() {
        System.out.println("cn.xm.controller.system.MyBean.MyBean");
    }

    public void print() {
        System.out.println("cn.xm.controller.system.MyBean.print");
    }
}

ObjectFactory

package cn.xm.controller.system;


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;

import java.io.Serializable;

public class MyBeanObjectFactory implements ObjectFactory<MyBean>, Serializable {

    public MyBeanObjectFactory() {
        System.out.println("cn.xm.controller.system.MyObjectFactory");
    }

    @Override
    public MyBean getObject() throws BeansException {
        return new MyBean();
    }
}

(2) 接口方式

package cn.xm.controller.system;


public interface MyInterface {

    public void print();
}

实现类:

package cn.xm.controller.system;

public class MyInterfaceImpl implements MyInterface {

    public MyInterfaceImpl() {
        System.out.println("cn.xm.controller.system.MyInterfaceImpl.MyInterfaceImpl");
    }

    @Override
    public void print() {
        System.out.println("cn.xm.controller.system.MyInterfaceImpl");
    }
}

ObjectFactory

package cn.xm.controller.system;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;

import java.io.Serializable;

public class MyInterfaceObjectFactory implements ObjectFactory<MyInterface>, Serializable {

    public MyInterfaceObjectFactory() {
        System.out.println("cn.xm.controller.system.MyObjectFactory");
    }

    @Override
    public MyInterface getObject() throws BeansException {
        return new MyInterfaceImpl();
    }
}

2. 配置类

采用动态注册bean 的方法,注册到BeanFactory

package cn.xm.controller.system;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBeanConfiguration implements BeanFactoryAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        ConfigurableListableBeanFactory beanFactory1 = (ConfigurableListableBeanFactory) beanFactory;
        beanFactory1.registerResolvableDependency(MyBean.class, new MyBeanObjectFactory());
        beanFactory1.registerResolvableDependency(MyInterface.class, new MyInterfaceObjectFactory());
    }

}

3. 注册到controller 查看其注入的类

    @Autowired
    private MyBean myBean;

    @Autowired
    private MyInterface myInterface;

    @GetMapping("/test1")
    public JSONResultUtil<String> test1(ServletRequest request1, ServletResponse response2) {
        System.out.println("======");
        System.out.println(request.getParameter("param1"));
        System.out.println(request1.getParameter("param1"));
        myBean.print();
        myInterface.print();
        return new JSONResultUtil<>(true, "ok", "test1");
    }

4. 访问查看其打印信息以及对象信息

访问: http://localhost:8088/test/test1?param1=t2

控制台打印信息如下:

======
t2
t2
cn.xm.controller.system.MyBean.print
cn.xm.controller.system.MyInterfaceImpl.MyInterfaceImpl
cn.xm.controller.system.MyInterfaceImpl

  可以看到对于接口注入的类调用的时候会调用getObject 方法创建对象,然后调用其方法; 对于类对象,会在启动过程中IOC 过程就自动调用getObject 方法获取对象。

2. ObjectFactory原理

  下面研究其原理。

1. ObjectFactory 和 FactoryBean 的区别

  前面了解到FactoryBean 是一个工厂对象,用于生产对象。我们注入FactoryBean 的时候实际会向容器中注册两个对象,一个是factoryBean 自身,一个是其getObject() 对象返回的对象。

  ObjectFactory 对象直白的意思就是对象工厂,其在Spring 可以动态注册一些对象。源码如下:

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/**
 * Defines a factory which can return an Object instance
 * (possibly shared or independent) when invoked.
 *
 * <p>This interface is typically used to encapsulate a generic factory which
 * returns a new instance (prototype) of some target object on each invocation.
 *
 * <p>This interface is similar to {@link FactoryBean}, but implementations
 * of the latter are normally meant to be defined as SPI instances in a
 * {@link BeanFactory}, while implementations of this class are normally meant
 * to be fed as an API to other beans (through injection). As such, the
 * {@code getObject()} method has different exception handling behavior.
 *
 * @author Colin Sampaleanu
 * @since 1.0.2
 * @see FactoryBean
 */
public interface ObjectFactory<T> {

    /**
     * Return an instance (possibly shared or independent)
     * of the object managed by this factory.
     * @return an instance of the bean (should never be {@code null})
     * @throws BeansException in case of creation errors
     */
    T getObject() throws BeansException;

}

2. 查看其注入到上面对象的实例

   可以看到对于对象注入的直接是对象自身,上面可以看出对于MyBean 注入的是MyBean 对象自身; 对于接口注入的会注入一个JDK动态代理对象。

查看org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler 对象源码如下:

    /**
     * Reflective InvocationHandler for lazy access to the current target object.
     */
    @SuppressWarnings("serial")
    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();
            }
            try {
                return method.invoke(this.objectFactory.getObject(), args);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }

  可以看到调用invoke 方法中, 如果调用的是其他方法会调用objectFactory.getObject() 方法,然后反射调用方法。

3. 查看其调用原理

1. 动态注册原理

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerResolvableDependency

    /** Map from dependency type to corresponding autowired value */
    private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);
    
    @Override
    public void registerResolvableDependency(Class<?> dependencyType, 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);
        }
    }

  可以看到是将类型放入 resolvableDependencies 内部的一个并发Map 中。

2. 接下来研究其注入的过程

  以注入 cn.xm.controller.system.MyInterface 为例子。

1》 在ioc 过程中注入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 开始依赖注入,接下来注入过程中会调用到:org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates

 1     protected Map<String, Object> findAutowireCandidates(
 2             String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
 3 
 4         String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
 5                 this, requiredType, true, descriptor.isEager());
 6         Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
 7         for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
 8             if (autowiringType.isAssignableFrom(requiredType)) {
 9                 Object autowiringValue = this.resolvableDependencies.get(autowiringType);
10                 autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
11                 if (requiredType.isInstance(autowiringValue)) {
12                     result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
13                     break;
14                 }
15             }
16         }
17         for (String candidate : candidateNames) {
18             if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
19                 addCandidateEntry(result, candidate, descriptor, requiredType);
20             }
21         }
22         if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
23             // Consider fallback matches if the first pass failed to find anything...
24             DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
25             for (String candidate : candidateNames) {
26                 if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
27                     addCandidateEntry(result, candidate, descriptor, requiredType);
28                 }
29             }
30             if (result.isEmpty()) {
31                 // Consider self references as a final pass...
32                 // but in the case of a dependency collection, not the very same bean itself.
33                 for (String candidate : candidateNames) {
34                     if (isSelfReference(beanName, candidate) &&
35                             (!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
36                             isAutowireCandidate(candidate, fallbackDescriptor)) {
37                         addCandidateEntry(result, candidate, descriptor, requiredType);
38                     }
39                 }
40             }
41         }
42         return result;
43     }

  可以看到这里在第7行的循环地方会先从自己的缓存map里面拿,当获取到匹配的类型之后获取到动态注入过程中的对象。上面获取到的对象就是cn.xm.controller.system.MyInterfaceObjectFactory。

2》 接下来调用 org.springframework.beans.factory.support.AutowireUtils#resolveAutowiringValue 解析自动注入的对象

    /**
     * Resolve the given autowiring value against the given required type,
     * e.g. an {@link ObjectFactory} value to its actual object result.
     * @param autowiringValue the value to resolve
     * @param requiredType the type to assign the result to
     * @return the resolved value
     */
    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;
    }

  可以看到如果获取到的对象 autowiringValue 是ObjectFactory, 并且该对象不是需要注入的对象的类型。会进入if 代码块。

  然后if 代码块里面判断如果对应的ObjectValue 实现了Serializable 接口, 并且需要的类型是接口的话,会用JDK的Proxy.newInstance 创建代理对象; 如果不满足前面条件就直接调用factory.getObject() 获取对象,然后直接注入对象自身。

  这里也就验证了上面,MyBean 注入的是MyBean 对象自身; 对于接口MyInterface 注入的会注入一个JDK动态代理对象。

3. 对于spring 注入的代理对象

  我们将断点放到org.springframework.beans.factory.support.DefaultListableBeanFactory#registerResolvableDependency 可以查看采用上面方式注入的主要有下面两类对象:

1. org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory 过程中注入一些对象如下:

        // BeanFactory interface not registered as resolvable type in a plain factory.
        // MessageSource registered (and found for autowiring) as a bean.
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

2. 容器启动过程中会调用到: org.springframework.web.context.support.WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, javax.servlet.ServletContext) 注入相关request、response等对象

(1) 调用链如下: 可以看到是在Spring事件中触发动态注册

 (2) 核心源码如下:

    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);
        }
    }

 4. ServletResquest、ServletResponse 注入原理

1. 采用下面方式注入ServletRequest和ServletResponse

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private HttpServletRequest request;

    @GetMapping("/test1")
    public JSONResultUtil<String> test1(ServletRequest request1, ServletResponse response2) {
        System.out.println("======");
        System.out.println(request.getParameter("param1"));
        System.out.println(request1.getParameter("param1"));
        return new JSONResultUtil<>(true, "ok", "test1");
    }

  注入的实际上是一个代理对象,不需要考虑单例实例的问题, 因为注入的是代理对象,每次都会调用ObjectFactory.getObject() 获取对象。我们注入的对象实际如下:

   可以看到Autowired 方式注入的对象实际是代理对象。 可以看到实际是org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler, 该类源码如下:

    /**
     * Reflective InvocationHandler for lazy access to the current target object.
     */
    @SuppressWarnings("serial")
    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();
            }
            try {
                return method.invoke(this.objectFactory.getObject(), args);
            }
            catch (InvocationTargetException ex) {
                throw ex.getTargetException();
            }
        }
    }
View Code

  以Request 为例子,实际会调用org.springframework.web.context.support.WebApplicationContextUtils.RequestObjectFactory 类获取ServletRequest 对象。 org.springframework.web.context.support.WebApplicationContextUtils.RequestObjectFactory 如下:

    /**
     * Factory that exposes the current request object on demand.
     */
    @SuppressWarnings("serial")
    private static class RequestObjectFactory implements ObjectFactory<ServletRequest>, Serializable {

        @Override
        public ServletRequest getObject() {
            return currentRequestAttributes().getRequest();
        }

        @Override
        public String toString() {
            return "Current HttpServletRequest";
        }
    }

    ...

    /**
     * Return the current RequestAttributes instance as ServletRequestAttributes.
     * @see RequestContextHolder#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;
    }

  会调用 org.springframework.web.context.request.RequestContextHolder#currentRequestAttributes 获取请求属性:

    private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
            new NamedThreadLocal<RequestAttributes>("Request attributes");

    private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
            new NamedInheritableThreadLocal<RequestAttributes>("Request context");

    public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
        RequestAttributes attributes = getRequestAttributes();
        if (attributes == null) {
            if (jsfPresent) {
                attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
            }
            if (attributes == null) {
                throw new IllegalStateException("No thread-bound request found: " +
                        "Are you referring to request attributes outside of an actual web request, " +
                        "or processing a request outside of the originally receiving thread? " +
                        "If you are actually operating within a web request and still receive this message, " +
                        "your code is probably running outside of DispatcherServlet/DispatcherPortlet: " +
                        "In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
            }
        }
        return attributes;
    }

    public static RequestAttributes getRequestAttributes() {
        RequestAttributes attributes = requestAttributesHolder.get();
        if (attributes == null) {
            attributes = inheritableRequestAttributesHolder.get();
        }
        return attributes;
    }

  可以看到是从ThreadLocal 中获取相关属性对象,接下来研究其创建过程。

2. 属性对象放入ThreadLocal 时机

(1) 方法org.springframework.web.context.request.RequestContextHolder#setRequestAttributes(org.springframework.web.context.request.RequestAttributes, boolean) 源码如下:

    /**
     * Bind the given RequestAttributes to the current thread.
     * @param attributes the RequestAttributes to expose,
     * or {@code null} to reset the thread-bound context
     * @param inheritable whether to expose the RequestAttributes as inheritable
     * for child threads (using an {@link InheritableThreadLocal})
     */
    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();
            }
        }
    }

 (2) 调用链如下:

  可以看到是在一个filter 中存入的相关对象。

org.springframework.web.filter.RequestContextFilter 过滤器源码如下:

package org.springframework.web.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Servlet Filter that exposes the request to the current thread,
 * through both {@link org.springframework.context.i18n.LocaleContextHolder} and
 * {@link RequestContextHolder}. To be registered as filter in {@code web.xml}.
 *
 * <p>Alternatively, Spring's {@link org.springframework.web.context.request.RequestContextListener}
 * and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose
 * the same request context to the current thread.
 *
 * <p>This filter is mainly for use with third-party servlets, e.g. the JSF FacesServlet.
 * Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.
 *
 * @author Juergen Hoeller
 * @author Rod Johnson
 * @author Rossen Stoyanchev
 * @since 2.0
 * @see org.springframework.context.i18n.LocaleContextHolder
 * @see org.springframework.web.context.request.RequestContextHolder
 * @see org.springframework.web.context.request.RequestContextListener
 * @see org.springframework.web.servlet.DispatcherServlet
 */
public class RequestContextFilter extends OncePerRequestFilter {

    private boolean threadContextInheritable = false;


    /**
     * Set whether to expose the LocaleContext and RequestAttributes as inheritable
     * for child threads (using an {@link java.lang.InheritableThreadLocal}).
     * <p>Default is "false", to avoid side effects on spawned background threads.
     * Switch this to "true" to enable inheritance for custom child threads which
     * are spawned during request processing and only used for this request
     * (that is, ending after their initial task, without reuse of the thread).
     * <p><b>WARNING:</b> Do not use inheritance for child threads if you are
     * accessing a thread pool which is configured to potentially add new threads
     * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
     * since this will expose the inherited context to such a pooled thread.
     */
    public void setThreadContextInheritable(boolean threadContextInheritable) {
        this.threadContextInheritable = threadContextInheritable;
    }


    /**
     * Returns "false" so that the filter may set up the request context in each
     * asynchronously dispatched thread.
     */
    @Override
    protected boolean shouldNotFilterAsyncDispatch() {
        return false;
    }

    /**
     * Returns "false" so that the filter may set up the request context in an
     * error dispatch.
     */
    @Override
    protected boolean shouldNotFilterErrorDispatch() {
        return false;
    }

    @Override
    protected void doFilterInternal(
            HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
        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);
        RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
        if (logger.isDebugEnabled()) {
            logger.debug("Bound request context to thread: " + request);
        }
    }

    private void resetContextHolders() {
        LocaleContextHolder.resetLocaleContext();
        RequestContextHolder.resetRequestAttributes();
    }

}

  可以看到相关的存、放操作都是在org.springframework.web.filter.RequestContextFilter#doFilterInternal 方法中完成的。

  到这里也就明白了关于Request、Response 对象的存放原理,以及其自动注入基于JDK 动态代理的原理。

 

posted @ 2022-05-05 23:09  QiaoZhi  阅读(2093)  评论(0编辑  收藏  举报