[Spring] [IOC] 容器的扩展类 BeanPostProcesser vs BeanFactoryPostProcesser vs FactoryBean - Gukie/learning GitHub Wiki
BeanPostProcessor
在bean的初始化前后,做一些用户自定义的工作,比较常用的是在初始化好之后将bean的实例应用到AOP代理中
它的两个方法是: postProcessBeforeInitialization postProcessAfterInitialization
需要注意的是
- 如果一个Bean实现了 BeanPostProcessor,那么所有的Bean在初始化的前后都会 去调用 BeanPostProcessor-Bean的postProcessBeforeInitialization和postProcessAfterInitialization方法
- 而 InitializingBean's afterPropertiesSet 或者说是 用户自定义的 init-method则是在 BeanPostProcessor-Bean的两个方法的中间
从BeanFactory的javaDoc中可以看到一个Bean的初始化过程的整体顺序: Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:
- BeanNameAware's setBeanName
- BeanClassLoaderAware's setBeanClassLoader
- BeanFactoryAware's setBeanFactory
- EnvironmentAware's setEnvironment
- EmbeddedValueResolverAware's setEmbeddedValueResolver
- ResourceLoaderAware's setResourceLoader (only applicable when running in an application context)
- ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context)
- MessageSourceAware's setMessageSource (only applicable when running in an application context)
- ApplicationContextAware's setApplicationContext (only applicable when running in an application context)
- ServletContextAware's setServletContext (only applicable when running in a web application context)
- postProcessBeforeInitialization methods of BeanPostProcessors
- InitializingBean's afterPropertiesSet
- a custom init-method definition
- postProcessAfterInitialization methods of BeanPostProcessors
BeanFactoryPostProcessor
BeanFactoryPostProcessor 是在容器中的所有bean开始实例化之前对metadata进行一些修改(所谓的metadata就是bean的定义,比如类的field是什么,field的值是多少) 可以通过实现BeanFactoryPostProcessor,对bean的definition进行一些修改. 如果是想对Bean的实例做一些修改,可以通过BeanPostProcessor进行
BeanFactoryPostProcessor operates on the bean configuration metadata; that is, the Spring IoC container allows a BeanFactoryPostProcessor to read the configuration metadata and potentially change it before the container instantiates any beans other than BeanFactoryPostProcessors
BeanPostProcessors 跟 BeanFactoryPostProcessor在容器启动的时候,就会被检查到并被实例化出来; 所以lazy initialization对它们是无效的
BeanFactoryPostProcessor的两个实现, PropertyOverrideConfigurer vs PropertyPlaceholderConfigurer
PropertyOverrideConfigurer,PropertyPlaceholderConfigurer 它们都是在bean的实例化之前,对bean的metadata做一些修改; 不同的是:
- PropertyOverrideConfigurer,是push的方式,会从properties文件中将bean的metadata信息覆盖掉
- PropertyPlaceholderConfigurer,是pull的方式,会从从properties文件中获取值,然后替代掉 占位符中的值; 通过它可以设置一个默认值,语法如下:
<property name="url" value="jdbc:${dbname:defaultdb}"/>
FactoryBean
FactoryBean一般用户架构的基础层,对一些构造过程负载的bean可以考虑采用它; 比如 读取xml中的list,set,map,就会用到, 他们对应的FactoryBean是:
- ListFactoryBean
- MapFactoryBean
- SetFactoryBean
它的getObjectType()和 getObject()两个方法,会在启动的时候就被调用,一般会早于post-processor bean的创建
FactoryBean is a programmatic contract. Implementations are not supposed to rely on annotation-driven injection or other reflective facilities. getObjectType() getObject() invocations may arrive early in the bootstrap process, even ahead of any post-processor setup. If you need access other beans, implement BeanFactoryAware and obtain them programmatically.
FactoryBean factoryBean = (FactoryBean) context.getBean("&customFactoryBean");
Class<?> cls = factoryBean.getObjectType();
System.out.println(cls.getName());
FactoryBean1 factoryBean1 = (FactoryBean1) context.getBean("customFactoryBean");
System.out.println(factoryBean1.getName());
@Component
public class CustomFactoryBean implements FactoryBean<FactoryBean1> {
@Nullable
@Override
public FactoryBean1 getObject() throws Exception {
// 这里可以定义复杂的 bean的创建
FactoryBean1 result = new FactoryBean1();
result.setName("created from factoryBean");
return result;
}
@Nullable
@Override
public Class<?> getObjectType() {
return FactoryBean1.class;
}
@Override
public boolean isSingleton() {
return false;
}
public class FactoryBean1 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}