Spring嵌套代理工厂对象问题
11 Sep 20141.问题场景
项目中需要在service层调用外围系统的Restful Web Service接口, 采用了resteasy的代理工厂类”RestClientProxyFactoryBean”来构造接口的客户端, 同时也需要在service层配置声明式事务, 为了统一配置风格, 因此并没有采用@Transactional的注解方式, 而是选择了通过另一个工厂代理类”TransactionProxyFactoryBean”加以实现.
配置如下:
<bean id="txBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<property name="transactionManager" ref="txManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
<bean id="restfulServiceProxy" class="org.jboss.resteasy.client.spring.RestClientProxyFactoryBean">
<property name="httpClient"><ref bean="httpClient"/></property>
<property name="serviceInterface" value="com.github.clarkdo.RestfuleService"/>
<property name="baseUri" value="${baseUrl}"/>
</bean>
<bean id="serviceProcessor" parent="txBase">
<property name="target">
<bean class="com.github.clarkdo.ServiceProcessor">
<constructor-arg index="0" ref="restfuleServiceShim"/>
</bean>
</property>
</bean>
<context:component-scan base-package="com.github.clarkdo.shim" />
<context:annotation-config/>
部分代码如下:
public class RestfuleServiceShim {
private final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
private IRestfuleService service;
}
public class ServiceProcessor implements IProcessor{
private final Logger log = LoggerFactory.getLogger(getClass());
private final RestfuleServiceShim serviceShim;
public ServiceProcessor(RestfuleServiceShim serviceShim) {
this.serviceShim = serviceShim;
}
}
在调试过程中发现, serviceProcessor对象中的serviceShim对象被注入成功了, 但是serviceShim中的IRestfuleService对象却是null.
2.问题分析
对于此问题, 当下即怀疑是由于嵌套了两个ProxyFactoryBean导致的, 将:
<bean id="processor" parent="txBase">
<property name="target">
<bean class="com.github.clarkdo.Processor">
<constructor-arg index="0" ref="restfuleServiceShim"/>
</bean>
</property>
</bean>
改为:
<bean id="processor" class="com.github.clarkdo.Processor">
<constructor-arg index="0" ref="restfuleServiceShim"/>
</bean>
重新启动服务, 发现一切均正常, 更加确认了问题所在的位置.但是通过观察日志发现restfulServiceProxy对象以及被初始化了, 只是没有注入到RestfuleServiceShim中.
因此, 继续对spring源码进行debug.
由于”IRestfuleService service”是通过@Autowired进行依赖注入的, 因此此属性应该在AbstractAutowireCapableBeanFactory的populateBean方法中进行填充.
Spring对应源码:
/**
* Populate the bean instance in the given BeanWrapper with the property values
* from the bean definition.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param bw BeanWrapper with bean instance
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
applyPropertyValues(beanName, mbd, bw, pvs);
}
经过调试发现, 在配置了声明式时务时, 执行populateBean过程中, 当前BeanFactory的getBeanPostProcessors()只有3个, 但是当没有配置时, 会包含11个BeanPostProcessor, 其中就包括AutowiredAnnotationBeanPostProcessor, 也正是这个类会对@Autowired标签这设置的类进行处理.
设置BeanFactory的beanPostProcessors位置为AbstractBeanFactory的addBeanPostProcessor方法, AutowiredAnnotationBeanPostProcessor会在PostProcessorRegistrationDelegate的registerBeanPostProcessors中被注册, 此方法是Spring应用上下文AbstractApplicationContext内refresh方法中的registerBeanPostProcessors调用的.
堆栈信息如下:
registerBeanPostProcessors():188, PostProcessorRegistrationDelegate {org.springframework.context.support}
registerBeanPostProcessors():618, AbstractApplicationContext {org.springframework.context.support}
refresh():467, AbstractApplicationContext {org.springframework.context.support}
configureAndRefreshWebApplicationContext():403, ContextLoader {org.springframework.web.context}
initWebApplicationContext():306, ContextLoader {org.springframework.web.context}
contextInitialized():106, ContextLoaderListener {org.springframework.web.context}
Spring对应源码:
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
OrderComparator.sort(priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
OrderComparator.sort(orderedPostProcessors);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
OrderComparator.sort(internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
注册的Processor包括:
当配置了声明式事务时, restfuleServiceShim是在AbstractApplicationContext中invokeBeanFactoryPostProcessors下被创建的.
堆栈信息如下:
populateBean():1125, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
doCreateBean():537, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
createBean():475, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
getObject():304, AbstractBeanFactory$1 {org.springframework.beans.factory.support}
getSingleton():228, DefaultSingletonBeanRegistry {org.springframework.beans.factory.support}
doGetBean():300, AbstractBeanFactory {org.springframework.beans.factory.support}
getBean():195, AbstractBeanFactory {org.springframework.beans.factory.support}
resolveReference():328, BeanDefinitionValueResolver {org.springframework.beans.factory.support}
resolveValueIfNecessary():108, BeanDefinitionValueResolver {org.springframework.beans.factory.support}
resolveConstructorArguments():632, ConstructorResolver {org.springframework.beans.factory.support}
autowireConstructor():140, ConstructorResolver {org.springframework.beans.factory.support}
autowireConstructor():1114, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
createBeanInstance():1017, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
doCreateBean():504, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
...
doGetBean():300, AbstractBeanFactory {org.springframework.beans.factory.support}
getTypeForFactoryBean():1420, AbstractBeanFactory {org.springframework.beans.factory.support}
getTypeForFactoryBean():788, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
isTypeMatch():543, AbstractBeanFactory {org.springframework.beans.factory.support}
doGetBeanNamesForType():387, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeanNamesForType():354, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeansOfType():466, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeansOfType():459, DefaultListableBeanFactory {org.springframework.beans.factory.support}
findResteasyRegistrations():306, SpringBeanProcessor {org.jboss.resteasy.plugins.spring}
postProcessBeanFactory():242, SpringBeanProcessor {org.jboss.resteasy.plugins.spring}
invokeBeanFactoryPostProcessors():265, PostProcessorRegistrationDelegate {org.springframework.context.support}
invokeBeanFactoryPostProcessors():170, PostProcessorRegistrationDelegate {org.springframework.context.support}
invokeBeanFactoryPostProcessors():609, AbstractApplicationContext {org.springframework.context.support}
refresh():464, AbstractApplicationContext {org.springframework.context.support}
当没有配置声明式事务时, restfuleServiceShim缺是在AbstractApplicationContext中finishBeanFactoryInitialization下被创建的.
堆栈信息如下:
populateBean():1184, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
doCreateBean():537, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
createBean():475, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
getObject():304, AbstractBeanFactory$1 {org.springframework.beans.factory.support}
getSingleton():228, DefaultSingletonBeanRegistry {org.springframework.beans.factory.support}
doGetBean():300, AbstractBeanFactory {org.springframework.beans.factory.support}
getBean():195, AbstractBeanFactory {org.springframework.beans.factory.support}
resolveReference():328, BeanDefinitionValueResolver {org.springframework.beans.factory.support}
...
getSingleton():228, DefaultSingletonBeanRegistry {org.springframework.beans.factory.support}
doGetBean():300, AbstractBeanFactory {org.springframework.beans.factory.support}
getBean():195, AbstractBeanFactory {org.springframework.beans.factory.support}
preInstantiateSingletons():703, DefaultListableBeanFactory {org.springframework.beans.factory.support}
finishBeanFactoryInitialization():760, AbstractApplicationContext {org.springframework.context.support}
refresh():482, AbstractApplicationContext {org.springframework.context.support}
AbstractApplicationContext中的refresh处理顺序如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
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);
//此处注册AutowiredAnnotationBeanPostProcessor
// 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();
//配置声明式事务时,此处初始化Shim
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
对照堆栈信息不难发现, 在配置了声明式事务时, 初始化restfuleServiceShim的时机在注册AutowiredAnnotationBeanPostProcessor之前, 因此没有对@Autowired进行处理.
那么, 为什么会出现不同时机对restfuleServiceShim的初始化呢?
3.结论
restfuleServiceShim初始化提前的问题就出现在声明式事务TransactionProxyFactoryBean的配置上, 在初始化restfuleServiceShim有这样一行的堆栈中有这样几行:
doGetBean():300, AbstractBeanFactory {org.springframework.beans.factory.support}
getTypeForFactoryBean():1420, AbstractBeanFactory {org.springframework.beans.factory.support}
getTypeForFactoryBean():788, AbstractAutowireCapableBeanFactory {org.springframework.beans.factory.support}
isTypeMatch():543, AbstractBeanFactory {org.springframework.beans.factory.support}
doGetBeanNamesForType():387, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeanNamesForType():354, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeansOfType():466, DefaultListableBeanFactory {org.springframework.beans.factory.support}
getBeansOfType():459, DefaultListableBeanFactory {org.springframework.beans.factory.support}
findResteasyRegistrations():306, SpringBeanProcessor {org.jboss.resteasy.plugins.spring}
postProcessBeanFactory():242, SpringBeanProcessor {org.jboss.resteasy.plugins.spring}
invokeBeanFactoryPostProcessors():265, PostProcessorRegistrationDelegate {org.springframework.context.support}
此部分代码作用是resteasy的SpringBeanProcessor查找所有SpringBeanProcessor类型的bean并进行注册, 其中Spring的DefaultListableBeanFactory的doGetBeanNamesForType会将所有BeanDefinition取出并与ResteasyRegistration类型进行匹配, 在匹配过程中isTypeMatch方法会调用getTypeForFactoryBean获取FactoryBean的类型, 它最终调用doGetBean方法, 此方法内会创建代理对象.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
当声明式事务的工程代理类serviceProcessor默认为单例时候, 此处创建的代理对象就将作为当前IOC容器中唯一存在的serviceProcessor Bean, 但是此时的BeanFactory还没注册处理@Autowired的AutowiredAnnotationBeanPostProcessor, RestfuleServiceShim内的IRestfuleService因此为空.
解决方案
此问题的解决方案还是蛮多的,我大致想到了以下方法:
- 手动控制事务(简单粗暴,耦合性大).
- 修改声明式事务的配置方式(配置声明式事务的方式有多种, 本文暂不一一列出).
- 修改restfuleServiceShim中servie属性注入方式, 改为通过XML进行注入(restfulServiceProxy与Shim均为上游系统提供jar包, 不易修改维护).
- 在Processor中通过ApplicationContext获取restfulServiceProxy, 手动设置restfuleServiceShim中servie属性(与Spring有较大耦合).
- 将processor设置为scope=”prototype”(所在项目中processor只会注入到一个单例对象内,即使配置为prototype也不会有过多影响,因此采用此方法).