Spring扩展点探索之BeanFactoryPostProcessor

只需低头努力,剩下的交给时光,时间会公平地帮你处理这一切

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天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章