简体   繁体   中英

Spring autowire custom @ConfigurationProperties object by prefix

I would like to achieve not-trivial bean injection implementation.

I have a custom properties file:

@Getter
@Setter
@ConfigurationProperties
public class DatabaseProperties {
  private String url;
  private String username;
  private String password;
}

I Here is the configuration file:

@Configuration
@EnableConfigurationProperties(DatabaseProperties.class)
public class DBConfig {

  @Bean
  @ConfigurationProperties(prefix = "datasource.database1")
  public JdbcTemplate jdbcTemplateDatabase1(DatabaseProperties databaseProperties) {
    DataSource dataSource = new DriverManagerDataSource(
            databaseProperties.getUrl(),
            databaseProperties.getUsername(),
            databaseProperties.getPassword());
    return new JdbcTemplate(dataSource);
  }

  @Bean
  @ConfigurationProperties(prefix = "datasource.database2")
  public JdbcTemplate jdbcTemplateDatabase2(DatabaseProperties databaseProperties) {
    DataSource dataSource = new DriverManagerDataSource(
            databaseProperties.getUrl(),
            databaseProperties.getUsername(),
            databaseProperties.getPassword());
    return new JdbcTemplate(dataSource);
  }
}

The goal I want to achieve is to instantiate a new DatabaseProperties instance based on prefix.

There are two possible solutions:

  • create two beans of type DatabaseProperties using corresponding prefixes and two JdbcTemplate beans where parameter is qualified DatabaseProperties bean accordingly.
  • in each JdbcTemplate bean provide 3 parameters (String url, String username, String password) and inject them through @Value

BUT Is it possible to get rid of creating DatabaseProperties beans for each JdbcTemplate or using @Value?

To my knowledge, there is no way around the fact that if you want to have access to multiple databases Spring will not be able to do the magic for you. You will need to create the two JdbcTemplate Spring-managed beans and then inject them where needed using the @Qualifier annotation.

This approach has two benefits:

  1. It actually work;
  2. You are explicit about what you are doing. A Spring application has already a good load of magic happening in there, so we might want to avoid some additional one when we need something a little bit more custom and that is not that complex to achieve.

You don't need create a DatabaseProperties . Spring already does this for us on datasources and proprierties variable


@Configuration
public class ConfigDataSource {


    @Bean("datasource-1")  // this name will qualify on @autowired
    @ConfigurationProperties(prefix="spring.datasource.yourname-datasource-1") // this is the name for the prefix for datasource on .properties settings
    public DataSource dataSourcePostgres() {
        return DataSourceBuilder.create().build();
    }
    
    
    @Bean("datasource-2")  // this name will qualify on @autowired
    @ConfigurationProperties(prefix="spring.datasource.yourname-datasource-2") // this is the name for the prefix for datasource on .properties settings
    public DataSource dataSourceMySql() {
        return DataSourceBuilder.create().build();
    }
    
}

.properties

# Its required use the same name declared in bean
spring.datasource.yourname-datasource-1.url=...
spring.datasource.yourname-datasource-1.jdbcUrl=${spring.datasource.yourname-datasource-1}
spring.datasource.yourname-datasource-1.username=user
spring.datasource.yourname-datasource-1.password=pass
spring.datasource.yourname-datasource-1.driver-class-name=your.driver

spring.datasource.yourname-datasource-2.url=...
spring.datasource.yourname-datasource-2.jdbcUrl=${spring.datasource.yourname-datasource-2}
spring.datasource.yourname-datasource-2.username=user
spring.datasource.yourname-datasource-2.password=pass
spring.datasource.yourname-datasource-2.driver-class-name=your.driver

using on services


@Awtowired
@Qualifier("datasource-1")
private DataSource dataSource1;

@Awtowired
@Qualifier("datasource-2")
private DataSource dataSource2;

public testJdbcTemplate(){
     // You can qualifier JdbcTemplate below on bean and not necessary need instance on service
     JdbcTemplate jdbcTemplateDatasource1 = new JdbcTemplate(dataSource1);
     JdbcTemplate jdbcTemplateDatasource2 = new JdbcTemplate(dataSource2);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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