只需低头努力,剩下的交给时光,时间会公平地帮你处理这一切
BeanFactoryPostProcessor是用来处理BeanFactory中Bean属性的后置处理器,也就是说在Bean初始化之前,Spirng提供了一个钩子可以让你根据自己的实际情况修改Bean的属性,最常见的应用就是我们的Bean中会有一些占位符,那么在Bean实例化之前这些占位符肯定是要被实际的配置参数填充的,这个填充的过程就是通过BeanFactoryPostProcessor的后置处理完成的
定义
BeanFactoryPostProcessor接口很简单,只有一个方法
/**
* Allows for custom modification of an application context's bean definitions,
* adapting the bean property values of the context's underlying bean factory.
*
* <p>Application contexts can auto-detect BeanFactoryPostProcessor beans in
* their bean definitions and apply them before any other beans get created.
*
* <p>Useful for custom config files targeted at system administrators that
* override bean properties configured in the application context.
*
* <p>See PropertyResourceConfigurer and its concrete implementations
* for out-of-the-box solutions that address such configuration needs.
*
* <p>A BeanFactoryPostProcessor may interact with and modify bean
* definitions, but never bean instances. Doing so may cause premature bean
* instantiation, violating the container and causing unintended side-effects.
* If bean instance interaction is required, consider implementing
* {@link BeanPostProcessor} instead.
*
* @author Juergen Hoeller
* @since 06.07.2003
* @see BeanPostProcessor
* @see PropertyResourceConfigurer
*/
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
从注释可以看出来:
- BeanFactoryPostProcessor接口允许修改上下文中Bean的定义(definitions),可以调整Bean的属性
- 上下文可以自动检测BeanFactoryPostProcessor,并且在Bean实例化之前调用
注意事项:
- BeanFactoryPostProcessor可以在Bean实例化之前修改Bean的属性,但不适合在BeanFactoryPostProcessor中做Bean的实例化,这样会导致一些意想不到的副作用,就是不要把Spring玩坏了,若需要做Bean的实例化可以使用BeanPostProcessor
写个例子
1、定义一个User类
public class User {
private String userName;
private int age;
public User(String userName,int age){
this.userName = userName;
this.age = age;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2、配置类
@Component
public class Configuration {
@Bean(name = "user")
public User getUser(){
return new User("Jack",18);
}
}
3、测试类
public class Main {
public static void main(String[] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("org.kxg.springDemo.beanFactoryPostProcessor");
User user = applicationContext.getBean("user",User.class);
System.out.println(user.getUserName());
}
}
输出结果:
Jack
以上是一个Spring入门级的例子,把User对象注册到容器中,然后从容器中取出User对象,并且打印userName属性
下面我们自定义一个BeanFactoryPostProcessor来修改这个User对象的属性
1、自定义BeanFactoryPostProcessor
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("调用自定义BeanFactoryPostProcessor");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
System.out.println("开始修改属性的值");
beanDefinition.getPropertyValues().add("userName","Tom");
}
}
自定义一个MyBeanFactoryPostProcessor实现BeanFactoryPostProcessor接口,重写postProcessBeanFactory()方法来实现对User Bean定义的修改
2、将MyBeanFactoryPostProcessor注册到Spring容器中
@Component
public class Configuration {
@Bean(name = "user")
public User getUser(){
return new User("Jack",18);
}
@Bean
public BeanFactoryPostProcessor custom(){
return new MyBeanFactoryPostProcessor();
}
}
再次运行上面的main方法,运行结果如下:
调用自定义BeanFactoryPostProcessor
开始修改属性的值
Tom
从运行结果来看,虽然一开始定义User类的userName属性是Jack,但在MyBeanFactoryPostProcessor中将userName属性修改成Tom,最后获取到的User对象是修改后的对象,至此Bean的属性在实例化之前被修改了,这就是BeanFactoryPostProcessor的作用
源码分析
上面我们知道,BeanFactoryPostProcessor是在Bean被实例化之前对Bean的定义信息进行修改,那么Spring是如何实现对自定义BeanFactoryPostProcessor的调用的,下面通过源码来看一下,首先还是从refresh()方法入手,在refresh()方法中会调用invokeBeanFactoryPostProcessors(beanFactory);
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//主要是这一行
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
/**因代码太长,省略了***/
//这里从beanFacoty中通过BeanFactoryPostProcessor类型来获取Bean名称,就可以拿到我们自定义的BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
//这里是优先级的处理,如果我们有多个自定义的BeanFactoryPostProcessor,可以通过优先级来定义执行顺序
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
//这里先处理实现了PriorityOrdered接口的BeanFactoryPostProcessor,也就是定义了优先级的先处理
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
//再处理实现了Ordered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
//这里才到了处理普通的自定义BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
beanFactory.clearMetadataCache();
}
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
invokeBeanFactoryPostProcessors()方法的逻辑很简单,就是去遍历容器中的BeanFactoryPostProcessor,然后调用postProcessBeanFactory()方法,这个方法就是我们自定义BeanFactoryPostProcessor时需要去实现的方法,至此整个流程就已经很清晰了
总结
- BeanFactoryPostProcessor是用来处理BeanFacoty中Bean属性的后置处理器
- BeanFactoryPostProcessor接口只定义了一个简单的方法postProcessBeanFactory()
- BeanFactoryPostProcessor接口允许修改上下文中Bean的定义(definitions),可以调整Bean的属性
- 上下文可以自动检测BeanFactoryPostProcessor,并且在Bean实例化之前调用
- 注意事项:BeanFactoryPostProcessor可以在Bean实例化之前修改Bean的属性,但不适合在BeanFactoryPostProcessor中做Bean的实例化,这样会导致一些意想不到的副作用,就是不要把Spring玩坏了_ ,若需要做Bean的实例化可以使用BeanPostProcessor
如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您