看完该篇文章我们可以了解到为何要动态注册bean、动态注册bean的方式、注册和实例化的区别、spring是什么时候实例化bean的。
前阵子在给项目写组件的时候研究了下spring组件拓展流程,其中遇见了动态注册bean的操作,对于长期使用spring容器管理bean的同学来说动态注册bean应该是活久见系列,为此打算以组件中使用到的方式讲讲动态注册方面的相关解说。
在自定义组件的时候,需要自定义命名空间注册器,其中需要提供一个配置解析器ConfigDefinitionParser,配置解析器需要继承AbstractBeanDefinitionParser, 其中需要重写函数parseInternal,返回的是AbstractBeanDefinition类型的数据。为了返回AbstractBeanDefinition,我借鉴了其他spring内部组件的写法,这边就用到了动态注册bean了。
DefaultListableBeanFactory是spring容器注册bean的核心,是spring注册及加载bean的默认实现。
一句话来描述其应用那就是:在spring项目启动的时候通过DefaultListableBeanFactory注册所有的BeanDefinition后放入definition表,后面在我们使用的时候就可以直接从表中加载了。
在说到动态注册bean之前,要先提下BeanDefinition
这是从官方文档截出来的,对此我的理解是,BeanDefinition是bean在实例化之前存在spring容器中的一种状态。
分不清注册和实例化的同学们在这里内心应该是 ━━( ̄ー ̄*|||━━ wocao,实例化和注册,什么跟什么 。
别急,在文章最后会点一下实例化和注册的哈!
大致了解了这两个之后便可以真正讲解如何动态注册bean了
package com.example.testdemo.beanDefinitionBuilderTest.main; public class TestBean { private String str; private TestBean2 testBean2; public void setStr(String str) { this.str = str; } public void setTestBean2(TestBean2 testBean2) { this.testBean2 = testBean2; } @Override public String toString() { return "TestBean{" + "str='" + str + '/'' + ", testBean2=" + testBean2 + '}'; } } 复制代码
package com.example.testdemo.beanDefinitionBuilderTest.main; public class TestBean2 { private int a; public void setA(int a) { this.a = a; } @Override public String toString() { return "TestBean2{" + "a=" + a + '}'; } } 复制代码
主要main类,可分为三个步骤:定义、注册、再取出
package com.example.testdemo.beanDefinitionBuilderTest.main; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; public class BeanDefinitionBuilderExample { public static void main(String[] args) { init(); } private static void init() { // 构建DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册testBean2 registerTestBean2(beanFactory); // 注册testBean registerTestBean1(beanFactory); // 从DefaultListableBeanFactory中读取bean TestBean bean = beanFactory.getBean(TestBean.class); System.out.println(bean); } private static void registerTestBean1(DefaultListableBeanFactory beanFactory) { // 构建TestBean BeanDefinitionBuilder b1 = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class); // 添加属性 b1.addPropertyValue("str", "myStringValue"); // 添加testBean2引用 b1.addPropertyReference("testBean2", "testBean2"); // 注册TestBean beanFactory.registerBeanDefinition("testBean", b1.getBeanDefinition()); } private static void registerTestBean2(DefaultListableBeanFactory beanFactory) { // 构建TestBean2 BeanDefinitionBuilder b2 = BeanDefinitionBuilder.rootBeanDefinition(TestBean2.class); // 添加属性 b2.addPropertyValue("a", 1); // 注册TestBean2 beanFactory.registerBeanDefinition("testBean2", b2.getBeanDefinition()); } } 复制代码
运行后输出
TestBean{str='myStringValue', testBean2=TestBean2{a=1}}
关于如何给BeanDefinitionBuilder添加各种成员属性和构造传参可以直接查看api地址:
docs.spring.io/spring/docs…
BeanFactoryPostProcessor允许自定义BeanDefinition,使用的GenericBeanDefinition,然后再注册入DefaultListableBeanFactory。
这里只给出main类,和上面的例子的区别在于注册函数的不同
package com.example.testdemo.beanDefinitionBuilderTest.main; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; public class BeanDefinitionBuilderExample { public static void main(String[] args) { init(); } private static void init() { // 构建DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 注册testBean2 registerTestBean2(beanFactory); // 注册testBean registerTestBean1(beanFactory); // 从DefaultListableBeanFactory中读取bean TestBean bean = beanFactory.getBean(TestBean.class); System.out.println(bean); } rivate static void registerTestBean1(DefaultListableBeanFactory beanFactory) { // 构建TestBean GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setBeanClass(TestBean.class); // 添加属性 bd.getPropertyValues().add("str", "myStringValue"); // 添加testBean2引用 bd.getPropertyValues().add("testBean2", beanFactory.getBean("testBean2")); // 注册TestBean beanFactory.registerBeanDefinition("testBean", bd); } private static void registerTestBean2(DefaultListableBeanFactory beanFactory) { // 构建TestBean2 GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setBeanClass(TestBean2.class); // 添加属性 bd.getPropertyValues().add("a", 1); // 注册TestBean2 beanFactory.registerBeanDefinition("testBean2", bd); } } 复制代码
运行后输出
TestBean{str='myStringValue', testBean2=TestBean2{a=1}}
可以看到注册bean的时候对GenericBeanDefinition的处理是可以自定义了,最终运行效果也是一样的。
注册和实例化其实就是spring容器管理bean的一个过程,先有注册bean才有实例化bean。 那么spring什么时候实例化bean呢?这里可以分为2种情况
如果我们使用BeanFactory作为bean的工厂类,如我上面那样的,则所有的bean都是在第一次使用该Bean的时候实例化,也就是从容器get出来的时候。
如果我们使用ApplicationContext作为bean的工厂类,则又分为以下几种情况:
ApplicationContext由BeanFactory类派生而来,所以提供了更多面向实际应用的功能。 以上可以看出spring容器其实是很懒的!!!