当前位置: 首页 > 知识库问答 >
问题:

使用BeanDefinitionRegistryPostProcessor创建N个bean

喻子航
2023-03-14

我正在尝试使用BeanDefinitionRegistryPostProcessor动态创建N个bean。基于这个问题,我选择在我的用例中使用BeanDefinitionRegistryPostProcessor

我在应用程序中定义了以下内容。yml

app:
  downstream-services:
    rest:
      jsonPlaceHolder:
        url: https://jsonplaceholder.typicode.com/todos
        api-type: io.mateo.dynamicbeans.JsonPlaceHolderApi

它连接到一个configirationproperties类:https://github.com/ciscoo/dynamicbeans/blob/master/src/main/java/io/mateo/dynamicbeans/FeignConfigurationProperties.java

然后我想注入那个ConfiGiruationProperties类以及我在这里定义的工厂bean:https://github.com/ciscoo/dynamicbeans/blob/master/src/main/java/io/mateo/dynamicbeans/FeignClientAutoConfiguration.java

现在我有以下几点:

https://github.com/ciscoo/dynamicbeans/blob/master/src/main/java/io/mateo/dynamicbeans/FeignClientFactoryPostProcessor.java

@Component
public class FeignClientFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    private final FeignConfigurationProperties properties;
    private final FeignClientFactory feignClientFactory;

    public FeignClientFactoryPostProcessor(FeignConfigurationProperties properties, FeignClientFactory feignClientFactory) {
        this.properties = properties;
        this.feignClientFactory = feignClientFactory;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        properties.getDownstreamServices().getRest().forEach((beanName, props) -> makeClient(beanName, props, registry));
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // no-op
    }

    private void makeClient(String beanName, FeignClientProperties props, BeanDefinitionRegistry registry) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(props.getApiType());
        beanDefinition.setInstanceSupplier(() -> feignClientFactory.create(props));
        registry.registerBeanDefinition(beanName, beanDefinition);
    }
}

它应该创建的单个bean被注入到这里的服务类中:https://github.com/ciscoo/dynamicbeans/blob/master/src/main/java/io/mateo/dynamicbeans/JsonPlaceHolderService.java

我遇到的问题是:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.mateo.dynamicbeans.FeignClientFactoryPostProcessor]: No default constructor found; nested exception is java.lang.NoSuchMethodException: io.mateo.dynamicbeans.FeignClientFactoryPostProcessor.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1262) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    ... 17 common frames omitted
Caused by: java.lang.NoSuchMethodException: io.mateo.dynamicbeans.FeignClientFactoryPostProcessor.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3350) ~[na:na]
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2554) ~[na:na]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78) ~[spring-beans-5.1.2.RELEASE.jar:5.1.2.RELEASE]
    ... 18 common frames omitted

但是当我从两个属性和定义的构造函数中删除final关键字时,我会得到一个NullPointerException

那么,我如何动态创建N个bean,以便它们能够及时供我的@Service类使用呢?

我知道https://spring.io/projects/spring-cloud-openfeign.我在这里重新创建了我的问题,以说明我在动态创建SOAP客户端的不同项目中遇到的相同问题。

更新:做以下更改:https://github.com/ciscoo/dynamicbeans/commit/4f16de9d03271025cd65d95932a3e854c0619c29,现在我能够完成我的用例。

共有1个答案

尹乐邦
2023-03-14

正如您链接到的问题的答案所示,您不能将依赖项注入到bean工厂后处理器中。您需要以编程方式绑定它,而不是注入配置属性类。在Spring Boot 2. x中,这是使用BinderAPI实现的:

新的活页夹API也可以在@ConfigurationProperties之外直接在您自己的代码中使用。例如,以下内容将绑定到人名对象的列表

List<PersonName> people = Binder.get(environment)
    .bind("my.property", Bindable.listOf(PersonName.class))   
    .orElseThrow(IllegalStateException::new);

配置源可以像这样在YAML中表示:

my:
  property:
  - first-name: Jane
    last-name: Doe
  - first-name: John
    last-name: Doe
 类似资料:
  • 问题内容: 例如; 我正在使用此类: 如果我想创建N个点(originTwo,originThree … originN); 我可以使用像这样的for循环吗? 如果它是可能的; 我如何给他们起不同的名字? 问题答案: 您可以将它们放入数组。 他们会全部使用相同的,并在这些条件下。 如果你有数组和你可以做这样的: 如果您不喜欢数组,则可以使用列表: 您将其称为

  • 问题内容: java中有没有一种方法可以用指定数量的指定字符创建字符串?就我而言,我需要创建一个包含10个空格的字符串。我当前的代码是: 有没有更好的方法来完成同一件事。特别是我想快速(在执行方面)。 问题答案: for循环将由编译器优化。在像您这样的情况下,您无需自己担心优化。信任编译器。 顺便说一句,如果有一种方法可以创建一个包含n个空格字符的字符串,那么它的编码方式就和您刚才一样。

  • 我试图用Priorityqueue和自定义比较器实现MST,但是我在O(n)时间内用它构建最小堆时遇到了问题。问题是Priorityqueue只有一个构造函数允许在O(n)中创建Priorityqueue,但它不使用任何比较器作为参数。我想让它使用我的自定义比较器。有解决这个问题的方法吗?AddAll()将失去对MST使用最小堆的目的,因为它是O(nlogn)方法。这是我的代码。 我想使用的比较器

  • 如果可能的话;我怎么给他们取不同的名字?

  • 我想创建一个Spring Bean Factory后处理器,将Bean添加到当前的ApplicationContext中。 我的中有很多Web-Services定义,我想尽可能地减少。 配置如下所示: 因此,我用以下bean定义创建了一个@Configuration类: 这好多了!,但是我想把它减少得更多,所以我想创建一个名为@WebService定义的注释,并添加一个BeanFactoryPos

  • 问题内容: 我正在寻找以下所有替代方案,以创建一个包含1到N的JavaScript数组,其中N仅在运行时才知道。 在我看来,应该有一种没有循环的方法。 问题答案: 如果我能得到想要的结果,则需要一个数字数组,以后可以循环使用。 如果这是您所需要的,您可以代替吗? 然后在您要使用它时…(未优化,例如) 例如,如果您不需要在数组中 存储 任何内容,则只需要一个长度合适的容器即可进行迭代……这可能会更容