根据属性动态注册Spring Bean

2024-04-22

我正在使用最新的 Spring Boot 版本,并尝试根据中定义的内容动态创建 n 个 beanapplication.yaml文件。然后我想根据 bean 名称将这些 bean 注入到其他类中。

下面的代码是我想要实现的目标的一个非常简化的示例。自动配置通常是 spring boot starter 库的一部分,因此需要注册的 bean 数量未知。

@Slf4j
@Value
public class BeanClass {

    private final String name;

    public void logName() {
        log.info("Name: {}", name);
    }

}
@Component
@RequiredArgsConstructor
public class ServiceClass {

    private final BeanClass fooBean;
    private final BeanClass barBean;

    public void log() {
        fooBean.logName();
        barBean.logName();
    }

}
@Value
@ConfigurationProperties
public class BeanProperties {

    private final List<String> beans;

}
@Configuration
public class AutoConfiguration {

    // Obviously not correct
    @Bean
    public List<BeanClass> beans(final BeanProperties beanProperties) {
        return beanProperties.getBeans().stream()
                .map(BeanClass::new)
                .collect(Collectors.toList());
    }

}
@EnableConfigurationProperties(BeanProperties.class)
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        final ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        final ServiceClass service = context.getBean(ServiceClass.class);
        service.log();
    }

}
beansToMake:
  - fooBean
  - barBean

我在谷歌上尝试了多种建议,但没有任何效果,而且似乎已经过时了。我希望 Spring 的一个新功能能让这一切变得简单。


你可以实施BeanDefinitionRegistryPostProcessor界面 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.html注册BeanClassbeans的定义如下:

public class DynamicBeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor {

  public static final String PROPERTIES_PREFIX = "beans";
  private final List<String> beanNames;

  public DynamicBeanDefinitionRegistrar(Environment environment) {
    beanNames =
        Binder.get(environment)
            .bind(PROPERTIES_PREFIX, Bindable.listOf(String.class))
            .orElseThrow(IllegalStateException::new);
  }

  @Override
  public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
      throws BeansException {
    beanNames.forEach(
        beanName -> {
          GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
          beanDefinition.setBeanClass(BeanClass.class);
          beanDefinition.setInstanceSupplier(() -> new BeanClass(beanName));
          registry.registerBeanDefinition(beanName, beanDefinition);
        });
  }

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
      throws BeansException {}
}

由于在实例化bean之前需要属性,因此要注册BeanClass豆类的定义,@ConfigurationProperties不适合这种情况。反而,活页夹API https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes#configuration-property-binding用于以编程方式绑定它们。

Because BeanDefinitionPostProcessor对象必须在容器生命周期的早期实例化,@Bean方法应标记为静态@Configuration类,根据Spring文档 https://docs.spring.io/spring-framework/docs/5.0.x/javadoc-api/org/springframework/context/annotation/Bean.html.

@Configuration
public class DynamicBeanDefinitionRegistrarConfiguration {
  @Bean
  public static DynamicBeanDefinitionRegistrar beanDefinitionRegistrar(Environment environment) {
    return new DynamicBeanDefinitionRegistrar(environment);
  }
}

结果,您定义的所有 beanapplication.yml,注册为BeanClass beans:

beans: 
    - fooBean
    - barBean

以供参考:使用 BeanDefinitionRegistryPostProcessor 创建 N 个 Bean https://stackoverflow.com/questions/53462889/create-n-number-of-beans-with-beandefinitionregistrypostprocessor, 从属性文件创建 Spring Boot 动态 Bean https://stackoverflow.com/questions/48161636/spring-boot-dynamic-bean-creation-from-properties-file

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

根据属性动态注册Spring Bean 的相关文章

随机推荐

  • Android Gradle:找不到符号变量

    我在使用 gradle 构建时遇到错误 如下所示 error cannot find symbol variable image name 我在用着ContextCompat getDrawable getActivity R drawab
  • 在Python中将字符串截断为特定字节数

    如何将字符串截断为不超过 50 个字节 a asdfzx awelkjawletjawetr dlgawklejtwgasdgsdfgd sdfasdfsdafa rewgargasregawergedrhsedhesrdhrthdrfjy
  • Selenium WebDriver 和下拉框

    如果我想选择下拉框的一个选项 有多种方法可以实现 我一直用 driver findElement By id selection sendKeys Germany 但这并不是每次都有效 有时会选择另一个选项 所以我用谷歌搜索了一下 发现这段
  • 如何使用 awk 将一组重复的行转置为列

    我有一个文本文件 其中包含 7 列数据 格式如下 18030 AAJ51 FTO rs9939609 C 30090620 10 A T 18030 AAJ51 CAT rs1001179 C 11468118 10 C C 18030 A
  • 有没有比“手表制造”更明智的替代方案?

    我遇到了这个有用的提示 如果您经常处理文件并且希望它们自动构建 则可以运行 手表品牌 每隔几秒钟它就会重新运行一次 一切都会构建完成 然而 它似乎一直在吞噬所有的输出 我认为它可能更聪明 也许显示输出流 但抑制 全部 不做任何事情 这样如果
  • Like子句和sql注入

    我对这种情况存有疑问 我在存储过程中有这样的查询 SELECT column1 column2 FROM table1 WHERE column1 like column1 我的问题是 这容易受到 SQL 注入攻击吗 我需要将其更改为这样的
  • 如何在PDF文档之前显示加载屏幕

    在我们的应用程序中 我们有动态生成的 PDF 文档的链接 链接看起来像这样主机 22 5 file 3136 pdf所以对于浏览器来说它就像一个静态的 pdf 文档 单击链接时 它会打开一个新窗口 该窗口仅接收 PDF 文档 无 HTML
  • 仅使用本机库的 C# 简单游戏

    我可以找到一组java 2D 游戏教程 http zetcode com tutorials javagamestutorial and 安卓游戏教程 http obviam net index php table of contents
  • 计算数组中向量之间的最大距离

    假设我们有一个包含 n 个向量的数组 我们想要计算这些向量之间的最大欧氏距离 最简单 天真的 的方法是迭代数组 并为每个向量计算其与所有后续向量的距离 然后找到最大值 然而 这个算法会增长 n 1 相对于数组的大小 对于这个问题还有其他更有
  • 继续阅读 JavaScript 中的链接

    我有一个像传记这样的字段 其中包含文本 我需要在第一页上显示该字段的一半 部分 文本 然后出现继续阅读链接 单击该链接后 剩余文本将显示在同一页面上 我需要在 HTML 中实现这一点 谁能帮我 请注意 这是快速原型设计 如果你使用jquer
  • 可以在 iOS 6 中显示“App Store 模式”吗?

    是否可以在 iOS 6 中显示一个模式视图控制器来在 App Store 中展示我的应用程序 是的你可以 iOS6 看一眼SKStoreProductViewController https developer apple com libr
  • 如何在 Laravel 7.x 中从控制器返回视图时传递 cookie?

    在 laravel 7 x 中 有什么方法可以在返回视图时将 cookie 传递给客户端吗 类似于 return view welcome gt cookie name value min 嗯 我做了一些研究 发现有一些方法 我熟悉的两个是
  • 当给定闪光角度和速度时,计算物体的轨迹

    我正在尝试从大炮中发射炮弹并使其遵循现实的路径 射击角度根据大炮的方向而变化 自动定向到鼠标指针 所以我想弄清楚的是 当给定角度和设定速度时 如何沿着抛物线路径移动炮弹 我读到 这可以在没有复杂的三角学的情况下完成 在高中时从未听过 并且可
  • Rails 3 ActiveRecord API:.build 方法

    我对 Ruby RoR 相当陌生 一年多了 我注意到 RoR 或 Ruby 内部有几种不同的方法基本上做同样的事情 我想要得到某种澄清的一种方法是 build方法 什么时候使用它是有效的 或者如何以最好的方式使用它 算是一回事 Thanks
  • 使用 JQuery css 方法自定义 CSS 光标

    有没有办法使用 JQuery 的 css 方法来提供以下光标样式 cursor url http www google com intl en ALL mapfiles closedhand cur default important jQ
  • 使用 pg-promise 查询多对多关系的最佳方法

    例如 我想从数据库获取用户信息 电子邮件及其角色 并创建一个如下对象 id 1 firstname John lastname Johnny emails type work email email protected cdn cgi l
  • 使用forever运行meteor生成的节点包的正确语法是什么?

    在文档中 在您自己的服务器上运行meteor的过程是运行 meteor bundle bundle tgz 然后提取这个 tarball tar xzvf bundle tgz 然后启动一个节点服务器 MONGO URL mongodb l
  • YouTube API v3 示例项目引发 GTLJSONRPCErrorDomain -32602 错误请求错误

    我刚刚下载了Google API 目标 C 客户端 https code google com p google api objectivec client source checkout 我在 Mac 上的 Xcode 中打开了 YouT
  • 如何在没有标志的情况下使用 ngx-bootstrap 角度折叠

    我正在尝试制作折叠动画 但没有布尔指示器isCollapsed 因为我有很多元素 并且我不想创建很多布尔值 所以有没有办法在没有布尔指示器的情况下做到这一点
  • 根据属性动态注册Spring Bean

    我正在使用最新的 Spring Boot 版本 并尝试根据中定义的内容动态创建 n 个 beanapplication yaml文件 然后我想根据 bean 名称将这些 bean 注入到其他类中 下面的代码是我想要实现的目标的一个非常简化的