在研究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 动态代理的原理。
【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】