在Spring框架中,Bean是应用程序的核心组成部分,而BeanDefinition则是这些Bean的元数据表示。随着应用程序的复杂性增加,我们可能需要更灵活地定义和注册Bean。Spring框架提供了几个扩展点,允许我们以编程方式影响Bean的创建和定义过程。本文将深入探讨BeanDefinitionRegistryPostProcessor、ImportBeanDefinitionRegistrar和BeanFactoryPostProcessor这三个重要的扩展点。
1.BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个重要的扩展点,它允许你在Spring容器实例化bean之前修改bean的定义。BeanFactoryPostProcessor接口定义了一个postProcessBeanFactory方法,该方法在Spring IoC容器实例化所有的bean定义之后,但在实例化任何bean之前被调用。
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
示例:
修改BeanDefinition
public class BeanFactoryTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.example.beanFactory");
context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
context.refresh();
System.out.println( context.getBean("testBean1"));
}
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor->postProcessBeanFactory");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestBean2.class);
defaultListableBeanFactory.registerBeanDefinition("testBean1",beanDefinitionBuilder.getBeanDefinition());
}
}
@Component
public class TestBean1 {
}
public class TestBean2 {
}
上面的代码会进行修改TestBean1的BeanDefinition,如果我们将 context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());这行代码注释掉之后,这块代码的执行结果为:
我们把注释放开之后,执行的结果就会变成
这个是因为我们在MyBeanFactoryPostProcessor中进行修改了testBean1的BeanDefinition所以就会导致这个结论。
注册新的BeanDefinition
对上面的代码我们可以进行改造一下
public class BeanFactoryTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.example.beanFactory");
context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
context.refresh();
System.out.println( context.getBean("testBean1"));
System.out.println( context.getBean("testBean2"));
}
}
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor->postProcessBeanFactory");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestBean2.class);
defaultListableBeanFactory.registerBeanDefinition("testBean2",beanDefinitionBuilder.getBeanDefinition());
}
}
执行结果为:
上面的代码我们可以看到TestBean2这个类,我们并没有通过注解交给spring管理,但我们还是可以从spring容器中进行获取到TestBean2的对象信息。这是因为我们在MyBeanFactoryPostProcessor进行添加了TestBean2的BeanDefinition。
2.BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类。
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
相比于BeanFactoryPostProcessor多了一个postProcessBeanDefinitionRegistry方法。这个方法是是针对BeanDefinition进行一些修改的操作。那这块就有一个疑问了为何有了BeanFactoryPostProcessor还需要BeanDefinitionRegistryPostProcessor呢?这是为什么呢,我觉得最主要得原因是执行时机的不同。BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor这两个类执行的时机不一样.sprin在进行执行的时候,会先进行执行BeanDefinitionRegistryPostProcessor实现类的中的postProcessBeanDefinitionRegistry方法,然后在进行执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanFactory方法,最后再进行执行BeanFactoryPostProcessor的postProcessBeanFactory方法。
示例:
//实现BeanFactoryPostProcessor接口
@Component
public class TestParent implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("TestParent->postProcessBeanFactory");
}
}
//实现BeanDefinitionRegistryPostProcessor接口
@Component
public class TestSub implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("TestSub->postProcessBeanDefinitionRegistry");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("TestSub->postProcessBeanFactory");
}
}
代码执行结果:
可以针对BeanDefinitionRegistryPostProcessor优先于BeanFactoryPostProcessor的执行特性,做一些特定化的操作。
3.ImportBeanDefinitionRegistrar
ImportBeanDefinitionRegistrar接口中有一个核心方法是registerBeanDefinitions方法。
BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor这两个接口都可以进行修改BeanDefinition,也可以进行添加BeanDefinition的定义,但spring不是很推荐使用BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor来进行BeanDefinition的新增,修改等操作,是比较推荐使用ImportBeanDefinitionRegistrar来进行BeanDefinition的添加,修改等操作。这是为啥呢。因为BeanDefinitionRegistryPostProcessor可能会创建出来一个半成品的bean来,我们来举例说明。
刚开始的时候我们进行创建两个类TestBean和TestBean1,在TestBean类中进行使用TestBean1这个类并用@Bean注解进行声明。
/此处的TestBean是没有用@Compent注解进行修饰的
public class TestBean {
public TestBean(){
System.out.println("testBean");
}
@Bean
public TestBean1 getTestBean1(){
return new TestBean1();
}
}
public class TestBean1 {
public TestBean1(){
System.out.println("testBean1");
}
}
我们使用BeanDefinitionRegistryPostProcessor来进行添加TestBean的BeanDefinition。
@Component
public class TestSub implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("TestSub->postProcessBeanDefinitionRegistry");
BeanDefinitionBuilder testBeanDefinition= BeanDefinitionBuilder.genericBeanDefinition(TestBean.class);
registry.registerBeanDefinition("testBean",testBeanDefinition.getBeanDefinition());
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("TestSub->postProcessBeanFactory");
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext
context = new AnnotationConfigApplicationContext();
context.scan("com.spring.example.beanDefinition");
context.refresh();
}
这块我们进行执行的时候发现 只进行执行了TestBean的构造方法中逻辑,TestBean1的构造方法并没有进行执行。那如果我们需要进行TestBean1的构造方法的时候,那么就需要进行实现ImportBeanDefinitionRegistrar接口。并且使用@Import注解,下面是使用ImportBeanDefinitionRegistrar接口的示例:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder testBean= BeanDefinitionBuilder.genericBeanDefinition(TestBean.class);
registry.registerBeanDefinition("testBean",testBean.getBeanDefinition());
}
}
@Import(MyImportBeanDefinitionRegistrar.class)
public class Test {
}
4.总结
BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor,ImportBeanDefinitionRegistrar这三个类都可以进行BeanDefinition的添加,修改等操作。
BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor这两个类可以看成一个类,因为BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的一个子类。BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor这两个类的主要区别在于这两个类的执行时机不同,spring在执行的时候会首先进行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,其次进行执行BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法,最后再进行BeanFactoryPostProcessor的postProcessBeanFactory方法。
BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor在进行BeanDefinition的添加的时候,如果要进行添加BeanDefinition中有一些比较特殊的方法(例@Bean 注解),可能会导致一些bean的创建,会创建一些半成品的bean。想要创建成一个完整的Bean,还是得使用ImportBeanDefinitionRegistrar接口来进行操作BeanDefinition。