简体   繁体   English

Spring 从配置列表启动 2 实例化 Bean

[英]Spring Boot 2 Instanciating Bean from Configuration List

Hy all,大家好,

in my current application, I need to be able to load a number of database connections into my context (they are then used in camel routes, but thats not part of this question).在我当前的应用程序中,我需要能够将一些数据库连接加载到我的上下文中(然后将它们用于骆驼路线,但这不是这个问题的一部分)。
For this I have a List of settings in my application.yml file, where each entry is all that is needed for one connection:为此,我的 application.yml 文件中有一个设置列表,其中每个条目都是一个连接所需的全部内容:

    - name: mysql1
      jdbcUrl: "jdbc:mysql://localhost:3306/dbScheme"
      username: a
      password: a
    - name: mssql1
      jdbcUrl: "jdbc:sqlserver://localhost:1433;databaseName=dbScheme"
      username: a
      password: a

There is a variable amount of connections, that can be configured this way.有可变数量的连接,可以通过这种方式进行配置。
I need each of those configurations as a javax.sql.DataSource object/bean in the registy (bean name would be the name property from the configuration object):我需要将这些配置中的每一个配置为注册表中的javax.sql.DataSource对象/bean(bean 名称将是配置对象中的 name 属性):

DataSource dataSourceBean = DataSourceBuilder.create()
    .driverClassName(driverClassName) // Resolved automatically from the jdbcUrl
    .url(dataSourceFromYaml.getJdbcUrl())
    .username(dataSourceFromYaml.getUsername())
    .password(dataSourceFromYaml.getPassword())
    .build();

The question now is, how I do put those objects into the context as beans?现在的问题是,我如何将这些对象作为 bean 放入上下文中?
As I see it, its not possible with annotations, because we have a variable amount of objects and they are also not loaded into the context directly, but have to be created first.正如我所看到的,注释是不可能的,因为我们有可变数量的对象,它们也不会直接加载到上下文中,而是必须先创建。 (Or am I wrong here?) (或者我在这里错了吗?)

Thanks in advance for any ideas提前感谢您的任何想法
Chris克里斯

Edit:编辑:
To clarify: The two connections I put here are not the connections used in production, they are just an example.澄清一下:我在这里放的两个连接不是生产中使用的连接,它们只是一个例子。
The issue is, that they are configured in production and there can be any amount of them.问题是,它们是在生产中配置的,并且可以有任意数量。
I have no way of predicting how many there are and how they are named.我无法预测有多少以及它们是如何命名的。

You could use the following approach您可以使用以下方法

  1. create properties file application-dev.properties创建属性文件 application-dev.properties

     mysql1.jdbc.jdbcUrl=jdbc:mysql://localhost:3306/dbScheme mysql1.jdbc.username=a mysql1.jdbc.password=a mssql1.jdbc.jdbcUrl=jdbc:sqlserver://localhost:1433;databaseName=dbScheme mssql1.jdbc.username=a mssql1.jdbc.password=a
  2. Create configuration class创建配置 class

     @Configuration public class JDBCConfigExample { @Bean(name = "mysql1DataSource") @ConfigurationProperties(prefix = "mysql1.jdbc") public DataSource mysql1DataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "mssql1DataSource") @ConfigurationProperties(prefix = "mssql1.jdbc") public DataSource mssql1DataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "mysql1JdbcTemplate") public JdbcTemplate mysql1JdbcTemplate(@Qualifier("mysql1DataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "mssql1JdbcTemplate") public JdbcTemplate mssql1JdbcTemplate(@Qualifier("mssql1DataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } }
  3. After that you could use both JdbcTemplate and DataSource in any Spring managed bean by using Qualifier or name convention:之后,您可以使用限定符或命名约定在任何 Spring 托管 bean 中同时使用 JdbcTemplate 和 DataSource:

     private final JdbcTemplate mssql1JdbcTemplate;

If you don't have list of datasources beforehand and want to configure this dynamically you can do following thing:如果您事先没有数据源列表并且想要动态配置它,您可以执行以下操作:

1) In your application.yml: 1) 在您的 application.yml 中:

    datasources:
      ds1:
        name:
        pw: 
      ds2:
        name: 
        pw: 

2) Create properties class: 2)创建属性class:

@Configuration
@ConfigurationProperties(prefix = "datasources")
public class DataSourcesInfo {

    Map<String, DataSourceInfo> dataSources;

    public @Data static class DataSourceInfo {
        private String pw;
        private String name;
    }
}

In this map you will have list of entries for all datasources defined.在此 map 中,您将拥有定义的所有数据源的条目列表。

3) And now you can create beans dynamically: 3)现在您可以动态创建bean:

    @Configuration
    public class Config {
        @Autowired
        private GenericApplicationContext genericApplicationContext;

        @Autowired
        DataSourcesInfo properties;

        @PostConstruct
        public void createDataSources() {
            // iterate through properties and register beans
            genericApplicationContext.registerBean(dataSourceName, 
            DataSource.class,
            () -> {
              DataSource ds = new DataSource();
              ds.set(...);
              ....
              return ds;
            })
        }
    }

After trying a lot of different spring context objects I finally found one, that worked.在尝试了很多不同的 spring 上下文对象之后,我终于找到了一个,它有效。
Here is the solution:这是解决方案:

@Configuration
@ConfigurationProperties(prefix = "jdbc")
@RequiredArgsConstructor // Lombok
public class DataSourceBeanFactory {

  // The DataSourceConfiguration holds everything from one property object
  @Setter // Lombok
  private List<DataSourceConfiguration> dataSources;
  private final ConfigurableApplicationContext applicationContext;

  @PostConstruct
  public void resolveAndCreateDataSourceBeans() {
    dataSources.forEach(dataSourceFromYaml -> {
      /*
       * Code to resolve driver class name
       */
      String driverClassName = ....

      DataSource dataSourceBean = DataSourceBuilder.create()
          .driverClassName(driverClassName)
          .url(dataSourceFromYaml.getJdbcUrl())
          .username(dataSourceFromYaml.getUsername())
          .password(dataSourceFromYaml.getPassword())
          .build();

      applicationContext
          .getBeanFactory()
          .registerSingleton(dataSourceFromYaml.getName(), dataSourceBean);
    });
  }

Thank to everybody, that answered my question.谢谢大家,回答了我的问题。
Chris克里斯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM