SpringBean装配非主流用法——给已存在的对象设置属性

适用情况:
java代码里获得了一个对象,反序列化来的或者直接new的还是set进来的无所谓,这个对象依赖于ApplicationContext中配置的一些bean,需要注入依赖的bean。对象的具体类型未知,依赖哪些bean不确定。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class AutowireBeanProperties {
    public static void main(String[] args) throws Exception {
        /*
         * 创建ApplicationContext,这里为了简单示例就不写xml文件而是用代码构建了。
         * 下面的代码相对于xml文件里有这么个bean:
         * <bean id="component" class="AutowireBeanProperties.ComponentImpl" />
         */
        final ComponentImpl component = new ComponentImpl();
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext();
        context.addBeanFactoryPostProcessor(new BeanFactoryPostProcessor() {
             
            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
                beanFactory.registerSingleton("component", component);
            }
        });
        context.refresh();
        /*创建ApplicationContext结束*/
        ComponentAware componentAware = new ComponentAware();
        context.getBeanFactory().autowireBeanProperties(componentAware, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
        System.out.println(componentAware.getComponent() == component);
        context.close();
    }
     
    public static interface Component {
         
    }
     
    public static class ComponentImpl implements Component {
         
    }
    public static class ComponentAware {
        private Component component;
        public Component getComponent() {
            return component;
        }
        public void setComponent(Component component) {
            this.component = component;
        }
    }
}

直接把autowireBeanProperties方法文档复制过来:

Autowire the bean properties of the given bean instance by name or type. Can also be invoked with AUTOWIRE_NO in order to just apply after-instantiation callbacks (e.g. for annotation-driven injection).

Does not apply standard BeanPostProcessors callbacks or perform any further initialization of the bean. This interface offers distinct, fine-grained operations for those purposes, for example initializeBean. However, InstantiationAwareBeanPostProcessor callbacks are applied, if applicable to the configuration of the instance.

这个方法只设置对象的属性,AutowireCapableBeanFactory.configureBean方法会做更多事情,具体的看spring文档。

存在的问题
一个对象如果要这样装配注入依赖,就会和SpringBean配置文件产生不明显的依赖关系。AUTOWIRE_BY_NAME的话就依赖于配置文件中的bean id;AUTOWIRE_BY_TYPE则会依赖于bean类型。
而且这样的依赖不明显,可能修改一下SpringBean配置文件,然后某个看起来完全不相关的地方的代码就因为依赖注入失败挂了。

解决办法 
1:让问题提前暴露
在SpringBean配置文件里显示的配置一个需要运行时注入依赖的对象, 设置autowire属性,让Spring自动装配它,然后写一个类实现org.springframework.beans.factory.InitializingBean接口,在Spring装配完对象后检查依赖注入是否完整。
这样就能提前发现会出现的依赖注入失败问题。
2:明确可以注入的依赖的名称/类型
从上面的代码可以看出,是可以在没有xml文件的情况下创建一个ApplicationContext的,然后把可以注入的依赖全部加入到ApplicationContext里,只用这个ApplicationContext来做运行时依赖注入。从而可以保证所有约定的可以注入的依赖都是存在的,bean id也都是确定的。


你可能感兴趣的:(SpringBean装配非主流用法——给已存在的对象设置属性)