11 Sep 2014

Spring嵌套代理工厂对象问题

1.问题场景

项目中需要在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也不会有过多影响,因此采用此方法).

Tags:
0 comments