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

从属性文件创建Spring Boot动态Bean

蒲坚
2023-03-14

如何基于应用程序动态定义bean。yml文件?

例如,YAML文件如下所示:

service:
   host: http://localhost:8080/
   account:
     url: /account
     content-type: application/json
   registry:
     url: /registry
     content-type: application/xml

这将动态创建两个带有内容类型标题集的HTTPHeader。

下面是我现在如何定义bean:

@Bean
public HttpHeaders accountHeaders(
    @Value("${service.account.content-type}") String contentType
) {
    HttpHeaders headers = new HttpHeaders();
    headers.set(HttpHeaders.CONTENT_TYPE, contentType);
    return headers;
}

@Bean
public HttpHeaders registryHeaders(
    @Value("${service.registry.content-type}") String contentType
) {
    HttpHeaders headers = new HttpHeaders();
    headers.set(HttpHeaders.CONTENT_TYPE, contentType);
    return headers;
}

如果我需要添加更多endpoint,我需要复制并粘贴这些bean,这是我想要避免的。

注意:这些动态bean不需要任何其他bean。我不确定这是否有什么不同。它只需要加载配置。

共有3个答案

罗浩然
2023-03-14

用环境测试它,看起来它工作正常。但是,您必须在配置中外部化您的注册表以注入env。此处不强制使用活页夹<代码>环境。getProperty()也会以同样的方式工作。

@Configuration
public class DynamicBeansConfiguration {

    @Bean
    public BeanDefinitionRegistrar beanDefinitionRegistrar(Environment environment) {
        return new BeanDefinitionRegistrar(environment);
    }

    public class BeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor {
        private Environment environment;

        public BeanDefinitionRegistrar(Environment environment) {
            this.environment = environment;
        }

        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

            List<Developer> developers = Binder.get(environment)
                    .bind("developers", Bindable.listOf(Developer.class))
                    .orElseThrow(IllegalStateException::new);

            developers.forEach(developer -> {
                GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                beanDefinition.setBeanClass(Developer.class);
                beanDefinition.setInstanceSupplier(() -> new Developer(developer.getName()));
                registry.registerBeanDefinition(developer.getName(), beanDefinition);
            });
        }

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

应用属性:

developers=John,Jack,William
吕飞翼
2023-03-14

您可以如下所述注入所有属性(不确定如何使用您当前的属性结构,Spring允许有关属性注入的真正先进的功能,此处提供其他示例)

@ConfigurationProperties(prefix = "yourPrefix")
public class CustomProperties {

  private final Map<String, String> properties = new HashMap<>();

  @Autowired 
  private ApplicationContext applicationContext;      

  @PostConstruct
  public void init() {
    AutowireCapableBeanFactory beanFactory = this.applicationContext.getAutowireCapableBeanFactory();
    // iterate over properties and register new beans
  }

}

你可以手动注册bean,比如

beanFactory.registerSingleton("beanName", bean);

这里是动态bean注册的其他示例

幸鸿轩
2023-03-14

有几个选项:

  • 使用程序化(“功能性”)bean注册。这样,注册bean是一个函数,您可以使用for-loops和if/fe等。Aliaksei的示例演示了这一点,有点。我通常使用Application ContextLaunalizerSpringApplication Builder()中注册(而不是SpringApplication.run(...))。
  • 您可以使用重要性定义注册器。实现它,然后使用Bean定义注册bean。使用@导入(MyIbdr.class)导入该类。
package com.example.dynabeans;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

import java.util.UUID;

@SpringBootApplication
public class DynabeansApplication {

    public static void main(String[] args) {
        SpringApplication.run(DynabeansApplication.class, args);
    }

}

class Foo {

    private final String id = UUID.randomUUID().toString();

    @Override
    public String toString() {
        return "Foo{" + id + "}";
    }
}


@Component
class FooListener {

    private final Log log = LogFactory.getLog(getClass());

    FooListener(Foo[] foos) {
        log.info("there are " + foos.length + " " + Foo.class.getName() + " instances.");
    }

}

@Component
class LoopyBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    private final Log log = LogFactory.getLog(getClass());
    private final int max = (int) (Math.random() * 100);

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        log.info("registering " + max + " beans.");
        for (int i = 0; i < max; i++) {
            BeanDefinitionBuilder gdb = BeanDefinitionBuilder.genericBeanDefinition(Foo.class, () -> new Foo());
            AbstractBeanDefinition abd = gdb.getBeanDefinition();
            BeanDefinitionHolder holder = new BeanDefinitionHolder(abd, Foo.class.getName() + '#' + i, new String[0]);
            BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
        }
    }

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

    }
}
 类似资料:
  • 本文向大家介绍js中动态创建json,动态为json添加属性、属性值的实例,包括了js中动态创建json,动态为json添加属性、属性值的实例的使用技巧和注意事项,需要的朋友参考一下 如下所示: 在js中,一个[]认为是数组;{}认为是Json对象; var json = {}; 定义一个Json对象; 为Json对象赋值: json[aa] = "xx"; eval 解析json报错 提示缺少“

  • 在我的默认SpringBoot应用程序中,它具有依赖项,调用(带有)返回以下信息 但是,我的机器上有两个驱动器,所以我想查看它们的磁盘空间详细信息。所以我添加了一个配置文件: 现在,我的健康endpoint返回以下数据 (稍后我将考虑如何抑制默认的“diskSpace”条目) 然而,由于我可能想在不同的机器上运行我的应用程序,我想配置磁盘驱动器,以便在我的文件。 还加上 配置在启动期间加载并记录到

  • 我试图使一个属性文件在Java。可悲的是,当我启动Minecraft(因为这是Forge中的一个mod)时,文件不会创建。我会非常感谢任何帮助我的人。下面是代码:

  • 我有一个充满行的文件,其中每一行都有银行账户对象的属性。文件布局示例: 1, IE33483, alex,1,100,20, s 2,IE30983,乔,1,0,20,c 3,IE67983,汤姆,1,70,20,s 我试图创建一些代码,将搜索这个文件的用户输入(例如,他们输入他们的id,这是每行的第一个元素),并将使用这3个属性来创建一个对象。有什么帮助吗?这是我到目前为止所尝试的,但它似乎不适

  • 我在尝试添加

  • 问题内容: 我已经编写了一个PropertyUtils类(来自互联网),它将加载属性 而PropertiesUtil类如下所示 稍后,我可以通过调用PropertiesUtil.getProperty()方法来获取属性。 但是现在我要稍作修改,以便如果myApp.properties被用户修改/更改,则应再次加载 可能我需要FileWatcher类 但我的怀疑是 如何使用classpath:myA