首页 > 其他分享 >【架构师进阶必备】Spring - 运行时以四种方式动态注册 bean

【架构师进阶必备】Spring - 运行时以四种方式动态注册 bean

时间:2024-08-02 12:29:12浏览次数:13  
标签:时以 Spring void Bean public bean MyBean class

Spring — 运行时以四种方式动态注册 bean

在这里插入图片描述

1. 概述

在本教程中,我们将学习“使用 spring 动态注册 bean”或“在运行时动态将 bean 添加到 spring-context”。在Spring 应用程序中加载和删除 bean 时,无需在运行时重新启动应用程序即可完成此操作。

如果客户端代码需要注册不受 Spring 容器管理的对象,那么我们将需要使用 BeanDefinition 实例。
Spring 应用程序可以使用 BeanDefinitionRegistry 的以下方法来注册BeanDefinition :

void registerBeanDefinition(String beanName,BeanDefinition beanDefinition)

2. Bean定义

BeanDefinition 描述了一个 bean 实例。它具有 setter 方法,可用于以编程方式将 Spring 特定特征设置为 bean,例如,BeanDefinition #setScope(String scope)可用于设置除默认单例之外的范围。

3. GenericBeanDefinition

这是常用的BeanDefinition实现。

它允许指定 bean 类、bean 特性以及构造函数参数值和属性值。

4.动态注册bean

有很多方法可以实现这一点。我们将通过以下示例进行讨论。

  1. 通用Bean定义
  2. BeanDefinitionBuilder
  3. BeanFactoryPostProcessor
  4. BeanDefinitionRegistryPostProcessor

4.1 使用GenericBeanDefinition进行动态Bean注册

GenericBeanDefinition 是标准 bean 定义的一站式解决方案。与任何 bean 定义一样,它允许指定类以及可选的构造函数参数值和属性值。此外,可以通过“ parentName ”属性灵活地配置从父 bean 定义派生。

通常,使用此GenericBeanDefinition类来注册用户可见的 bean 定义(后处理器可能会对其进行操作,甚至可能重新配置父名称)。在父/子关系已预先确定的情况下,请使用RootBeanDefinition / ChildBeanDefinition 。

创建示例 Bean 类。

public class MyBean {
  private Date date;
  public void doSomething () {
      System.out.println("来自我的 bean,日期:" + date);
  }
  public void setDate (Date date) {
      this.date = date;
  }
}

使用GenericBeanDefinition动态注册上述创建的 bean 。

public class GenericBeanDefinitionExample 
{
  public static void main (String[] args) 
  {
      DefaultListableBeanFactory context = new DefaultListableBeanFactory();
      GenericBeanDefinition gbd = new GenericBeanDefinition();
      gbd.setBeanClass(MyBean.class);
      MutablePropertyValues mpv = new MutablePropertyValues();
      mpv.add("date", new Date());
      
      //alternatively we can use:
      // gbd.getPropertyValues().addPropertyValue("date", new Date());
      gbd.setPropertyValues(mpv);
      context.registerBeanDefinition("myBeanName", gbd);
      MyBean bean = context.getBean(MyBean.class);
      bean.doSomething();
  }
}

输出:

来自我的bean,日期:2019 年 7 月 23 日星期三 12:20:58 EDT

4.2 使用 BeanDefinitionBuilder 进行动态 Bean 注册

使用构建器模式构建BeanDefinitions的编程方法。主要用于实现 Spring 2.0 NamespaceHandlers。这里唯一的区别是,BeanDefinitionBuilder 使用Builder Pattern。

创建另一个 bean 类。

public class MyBean {
  private String str;
  public void setStr (String str) {
      this.str = str;
  }
  public void doSomething () {
      System.out.println("from MyBean " + str);
  }
}

使用BeanDefinitionBuilder动态注册 bean 的示例。

public class BeanDefinitionBuilderExample {
  public static void main (String[] args) {
      DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
      BeanDefinitionBuilder b = BeanDefinitionBuilder
      			.rootBeanDefinition(MyBean.class)
           .addPropertyValue("str", "myStringValue");
           
      beanFactory.registerBeanDefinition("myBean", b.getBeanDefinition());
      MyBean bean = beanFactory.getBean(MyBean.class);
      bean.doSomething();
  }
}

输出:

from MyBean myStringValue

使用 BeanDefinitionBuilder 注入其他 bean 引用
a. 创建 Bean 1

public class Bean1 {
  private Bean2 otherBean;
  public void setOtherBean (Bean2 otherBean) {
      this.otherBean = otherBean;
  }
  public void doSomething () {
      otherBean.doSomething();
  }
}

b. 创建 Bean 2

public class Bean2 {
  public void doSomething () {
      System.out.println("from other bean ");
  }
}

c. 在 Bean1 中设置 Bean2

public class InjectingOtherBeans {
  public static void main (String[] args) {
      DefaultListableBeanFactory context = new DefaultListableBeanFactory();
      
      //define and register MyOtherBean
      GenericBeanDefinition beanOtherDef = new GenericBeanDefinition();
      beanOtherDef.setBeanClass(Bean2.class);
      context.registerBeanDefinition("other", beanOtherDef);
      
      //definine and register myBean
      GenericBeanDefinition beanDef = new GenericBeanDefinition();
      beanDef.setBeanClass(Bean1.class);
      MutablePropertyValues mpv = new MutablePropertyValues();
      mpv.addPropertyValue("otherBean", context.getBean("other"));
      beanDef.setPropertyValues(mpv);
      context.registerBeanDefinition("myBean", beanDef);
      
      //using MyBean instance
      MyBean bean = context.getBean(MyBean.class);
      bean.doSomething();
  }
}

输出:

from other bean

4.3 使用 BeanFactoryPostProcessor 进行动态 Bean 注册

BeanFactoryPostProcessor可以与 bean 定义交互并修改 bean 实例,但绝不能与 bean 实例交互并修改 bean 定义。允许自定义修改应用程序上下文的 bean 定义,调整上下文底层 bean 工厂的 bean 属性值。应用程序上下文可以自动检测其bean 定义中的BeanFactoryPostProcessor bean,并在创建任何其他 bean 之前应用它们。

创建配置:

@Configuration
public class MyConfig {
  @Bean
  MyConfigBean myConfigBean () {
      return new MyConfigBean();
  }
}

BeanFactoryPostProcessor允许客户端代码自定义 bean 定义。BeanFactoryPostProcessor.postProcessBeanFactory 方法由 Spring 启动过程在加载所有 bean 定义但在尚未实例化任何 bean之前调用。

public class MyConfigBean implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
      GenericBeanDefinition bd = new GenericBeanDefinition();
      bd.setBeanClass(MyBean.class);
      bd.getPropertyValues().add("strProp", "my string property");
      ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition("myBeanName", bd);
  }
}

为该 Demo 创建另一个 Bean。

public class MyBean {
  private String strProp;
  public void setStrProp (String strProp) {
      this.strProp = strProp;
  }
  public void doSomething () {
      System.out.println("from MyBean:  " + strProp);
  }
}

创建BeanFactoryPostProcessor 示例的主类并运行。

public class BeanFactoryPostProcessorExample {
  public static void main (String[] args) {
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
      MyBean bean = context.getBean(MyBean.class);
      bean.doSomething();
  }
}

输出:

from MyBean:  my string property
WARNING: @Bean method MyConfig.myConfigBean is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.

4.4 使用 BeanDefinitionRegistryPostProcessor 进行动态 Bean 注册

对标准BeanFactoryPostProcessor SPI 的扩展,允许在常规 BeanFactoryPostProcessor 检测启动之前注册进一步的 bean 定义。特别是,BeanDefinitionRegistryPostProcessor可以注册进一步的 bean 定义,而这些 bean 定义又定义BeanFactoryPostProcessor实例。

创建另一个配置类:

@Configuration
public class MyConfig {
  @Bean
  MyConfigBean myConfigBean () {
      return new MyConfigBean();
  }
}

这是BeanFactoryPostProcessor (最后一个例子)的子接口。它允许注册 bean 定义。它的方法postProcessBeanDefinitionRegistry在BeanFactoryPostProcessor#postProcessBeanFactory之前被调用。这个接口更专注于 BeanDefinition 注册,而不是通用的BeanFactoryPostProcessor。

为 BeanDefinitionRegistryPostProcessor 创建实现类。

public class MyConfigBean implements BeanDefinitionRegistryPostProcessor {
  @Override
  public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry)
            throws BeansException {
      GenericBeanDefinition bd = new GenericBeanDefinition();
      bd.setBeanClass(MyBean.class);
      bd.getPropertyValues().add("strProp", "my string property");
      registry.registerBeanDefinition("myBeanName", bd);
  }
  @Override
  public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
      //no op
  }
}

创建一个全新的 Bean 类。

public class MyBean {
  private String strProp;
  public void setStrProp (String strProp) {
      this.strProp = strProp;
  }
  public void doSomething () {
      System.out.println("from MyBean:  " + strProp);
  }
}

创建BeanDefinitionRegistryPostProcessor 示例的主类并运行:

public class BeanDefinitionRegistryPostProcessorExample {
  public static void main (String[] args) {
      AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyConfig.class);
      MyBean bean = (MyBean) context.getBean("myBeanName");
      bean.doSomething();
  }
}

输出:

from MyBean:  my string property
WARNING: Cannot enhance @Configuration bean definition 'beanDefinitionRegistryPostProcessorExample.MyConfig' since its singleton instance has been created too early. The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.

5. 运行时注销 Bean

如果我们需要在运行时删除已注册的bean,我们可以按照下面的方法操作。

从 spring 上下文中删除或者取消注册该 bean。

beanRegistry.removeBeanDefinition("bean")

从上下文中删除/清除单例 bean。

beanRegistry.destroySingleton("bean")

6. 结论

在本文中,我们了解了如何在 Spring 框架中动态注册一个 bean。

本文详细展示了 GenericBeanDefinition、BeanDefinitionBuilder、BeanFactoryPostProcessor 和 BeanDefinitionRegistryPostProcessor 的示例程序。希望对大家有所帮助,感谢大家拜读~~!

标签:时以,Spring,void,Bean,public,bean,MyBean,class
From: https://blog.csdn.net/lilinhai548/article/details/140858925

相关文章