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。

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
动态创建bean是通过SpringBeanFactory和ApplicationContext接口实现的,可以使用以下代码创建动态bean: ``` // 创建一个BeanFactory DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); // 创建一个bean定义 RootBeanDefinition beanDef = new RootBeanDefinition(MyBean.class); // 设置属性 beanDef.getPropertyValues().add("propertyName", "propertyValue"); // 注册bean定义 factory.registerBeanDefinition("myBean", beanDef); // 获取bean MyBean myBean = (MyBean)factory.getBean("myBean"); ``` 上面的代码中,首先创建了一个DefaultListableBeanFactory对象,它是Spring中的一个bean工厂,用于创建和管理bean。然后,创建了一个RootBeanDefinition对象,它是bean的定义,可以设置bean的属性和依赖项。接下来,将bean定义注册BeanFactory中,并指定bean的名称。最后,通过getBean方法获取bean实例。 使用ApplicationContext创建动态bean的代码如下: ``` // 创建一个ApplicationContext ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(); // 创建一个bean定义 RootBeanDefinition beanDef = new RootBeanDefinition(MyBean.class); // 设置属性 beanDef.getPropertyValues().add("propertyName", "propertyValue"); // 注册bean定义 context.registerBeanDefinition("myBean", beanDef); // 启动ApplicationContext context.refresh(); // 获取bean MyBean myBean = (MyBean)context.getBean("myBean"); ``` 上面的代码中,首先创建了一个ClassPathXmlApplicationContext对象,它是ApplicationContext的一种实现,用于创建和管理bean。然后,创建了一个RootBeanDefinition对象,设置bean的属性和依赖项。接下来,将bean定义注册到ApplicationContext中,并指定bean的名称。最后,通过getBean方法获取bean实例。 需要注意的是,动态创建bean需要在Spring容器启动之前进行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小园子的小菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值