spring拓展点之ObjectFactory

前言

1
2
3
4
// 注入所有HttpMessageConverters

@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
  • 为什么需要objectFactory包装?

接口定义

1
2
3
4
5
6
7
8
9
10
11
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;

}

常见实现类

  1. RequestObjectFactory
  2. ResponseObjectFactory
  3. SessionObjectFactory
  4. WebRequestObjectFactory
  5. TargetBeanObjectFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public abstract class WebApplicationContextUtils {
/**
* 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";
}
}


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

@Override
public ServletResponse getObject() {
ServletResponse response = currentRequestAttributes().getResponse();
if (response == null) {
throw new IllegalStateException("Current servlet response not available - " +
"consider using RequestContextFilter instead of RequestContextListener");
}
return response;
}

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


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

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

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


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

@Override
public WebRequest getObject() {
ServletRequestAttributes requestAttr = currentRequestAttributes();
return new ServletWebRequest(requestAttr.getRequest(), requestAttr.getResponse());
}

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

}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 控制层基类
*/
public abstract class BaseController {

@Autowired
protected HttpServletRequest request;

@Autowired
protected HttpServletResponse response;

@Autowired
protected HttpSession session;
}

// 子类
@Controller
public class SystemController extends BaseController {
........
............
}

咋一看,是不是觉得存在线程安全问题? 在SpringMvc中Controller不是单例的吗?那request,response和session对象岂不是所有线程共享的,后面进来的请求岂不是会覆盖前面请求的这些对象。但事实上,官方已经给出证明example,这种写法是正确的,不会存在线程安全问题,下面来分析一下,Spring是如何实现的。

ps: ResponseObjectFactory 是从Spring 4版本以上才开始出现的。

实现原理

XmlWebApplicationContext是Spring提供的容器的一种实现,多运用于Web项目中。继承于AbstractRefreshableWebApplicationContext,而AbstractRefreshableWebApplicationContext重写了AbstractApplicationContext中的postProcessBeanFactory方法,向beanFactory容器中添加依赖解析映射关系。

AbstractApplicationContext:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// 加载Bean信息,并添加到容器中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// 调用子类重写的方法
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for registering special
* BeanPostProcessors etc in certain ApplicationContext implementations.
* @param beanFactory the bean factory used by the application context
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}

}

AbstractRefreshableWebApplicationContext是AbstractApplicationContext的子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

// 关键步骤:添加解析映射关系
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

}

WebApplicationContextUtils:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public abstract class WebApplicationContextUtils {

/**
* Register web-specific scopes ("request", "session", "globalSession", "application")
* with the given BeanFactory, as used by the WebApplicationContext.
* @param beanFactory the BeanFactory to configure
* @param sc the ServletContext that we're running within
*/
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);
}
}

}

当Spring容器启动的时候,会调用refresh方法,从而触发postProcessBeanFactory方法的执行。向beanFactory中添加依赖解析映射关系,当调用beanFactory.getBean方法获取实例时,注入依赖Bean则会使用到该依赖解析映射关系。

DefaultListableBeanFactory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

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

/**
* Find bean instances that match the required type.
* Called during autowiring for the specified bean.
* @param beanName the name of the bean that is about to be wired
* @param requiredType the actual type of bean to look for
* (may be an array component type or collection element type)
* @param descriptor the descriptor of the dependency to resolve
* @return a Map of candidate names and candidate instances that match
* the required type (never {@code null})
* @throws BeansException in case of errors
* @see #autowireByType
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
// 判断当前依赖Bean类型requiredType是否是autowiringType及其子类
if (autowiringType.isAssignableFrom(requiredType)) {
// 如果是则使用映射关系值,如:RequestObjectFactory等
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
// 关键步骤:生成JDK动态代理
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}

}

AutowireUtils:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
abstract class AutowireUtils {

/**
* 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()) {
// 如果是接口则生成基于JDK的动态代理
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
}
else {
// 不是接口则返回factory.getObject()对象
return factory.getObject();
}
}
// 返回原始值
return autowiringValue;
}

/**
* 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 {
// 通过反射调用,如RequestObjectFactory等中的方法
return method.invoke(this.objectFactory.getObject(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}

}

我们在回到WebApplicationContextUtils类中的RequestObjectFactory,看下其具体的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public abstract class WebApplicationContextUtils {

/**
* 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";
}
}

/**
* RequestContextHolder 从当前请求上下文中获取真实的Request,Response,Session等对象
* 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;
}

}

请求线程上下文管理器RequestContextHolder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public abstract class RequestContextHolder  {
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes");

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

/**
* 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();
}
}
}

/**
* Return the RequestAttributes currently bound to the thread.
* @return the RequestAttributes currently bound to the thread,
* or {@code null} if none bound
*/
public static RequestAttributes getRequestAttributes() {
RequestAttributes attributes = requestAttributesHolder.get();
if (attributes == null) {
attributes = inheritableRequestAttributesHolder.get();
}
return attributes;
}

/**
* Return the RequestAttributes currently bound to the thread.
* <p>Exposes the previously bound RequestAttributes instance, if any.
* Falls back to the current JSF FacesContext, if any.
* @return the RequestAttributes currently bound to the thread
* @throws IllegalStateException if no RequestAttributes object
* is bound to the current thread
* @see #setRequestAttributes
* @see ServletRequestAttributes
* @see FacesRequestAttributes
* @see javax.faces.context.FacesContext#getCurrentInstance()
*/
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;
}

}

当请求进来时,设置当前请求的上下文信息,RequestContextFilter类。RequestContextFilter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class RequestContextFilter extends OncePerRequestFilter {
@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();
}

}

至此,怎个流程算是串起来了,之所以不会存在线程安全问题,那是因为注入的是实现了HttpServletRequest, HttpServletResponse接口的动态代理对象,然后在这个动态代理对象中执行invoke时,获取当前线程上下文所关联的实际request,response等对象,再反射执行其中的方法。整体设计非常巧妙,设计思想值得学习和借鉴。

后记

objectFactory有实现类:org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider

通过它,可以实现bean的懒加载。即,第一次调用getObject时,解析所有spring管理的泛型bean,返回。