适用情况:
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也都是确定的。