Spring如何进行动态注册Bean

在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。

相关推荐

  1. spring系列-动态注册bean

    2024-07-17 18:08:03       40 阅读
  2. 如何动态Spring容器注册/移除bean

    2024-07-17 18:08:03       29 阅读
  3. 如何Spring管理bean进行增强

    2024-07-17 18:08:03       34 阅读
  4. Spring Boot 3】动态注入和移除Bean

    2024-07-17 18:08:03       41 阅读
  5. spring注册bean-AnnotationBeanDefinitionReader】

    2024-07-17 18:08:03       46 阅读
  6. Spring Boot项目中如何Bean进行校验

    2024-07-17 18:08:03       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 18:08:03       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 18:08:03       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 18:08:03       57 阅读
  4. Python语言-面向对象

    2024-07-17 18:08:03       68 阅读

热门阅读

  1. 鼠标的形状

    2024-07-17 18:08:03       19 阅读
  2. 视频网站适用于什么服务器类型呢?

    2024-07-17 18:08:03       22 阅读
  3. 重要的单元测试

    2024-07-17 18:08:03       21 阅读
  4. 软件测试bug周期

    2024-07-17 18:08:03       23 阅读
  5. #if defined(WEBRTC_USE) webrtc.a的宏机制

    2024-07-17 18:08:03       17 阅读
  6. bug【创作模板】

    2024-07-17 18:08:03       19 阅读
  7. 计算机视觉6 计算机视觉---风格迁移

    2024-07-17 18:08:03       21 阅读
  8. Python 可变参数 *args 和 **kwargs 的用法

    2024-07-17 18:08:03       17 阅读
  9. 加载中的css动画

    2024-07-17 18:08:03       22 阅读