Используйте @ConfigurationProperties над неуправляемым @Bean - PullRequest
2 голосов
/ 19 марта 2019

Я бы хотел воспользоваться @ConfigurationProperties фантастическими возможностями без необходимости выставлять боб в моем контексте.Это не проблема @Primaries и т.п., я просто не могу выставить еще один Datasource в контекст.Как я могу добиться следующего?

@ConfigurationProperties("com.non.exposed.datasource.hikari")
public DataSource privateHikariDatasource() {
    if (Objects.isNull(this.nonExposedDatasource)) {
        this.nonExposedDatasource = this.nonExposedDatasourceProperties.initializeDataSourceBuilder().build();
    }
    return this.nonExposedDatasource;
}

Благодаря ответу @LppEdd, окончательное идеальное решение:

@Autowired
private Environment environment;

public DataSource privateHikariDatasource() {
    if (Objects.isNull(this.nonExposedDatasource)) {
        this.nonExposedDatasource = bindHikariProperties(this.nonExposedDatasourceProperties.initializeDataSourceBuilder().build());
    }
    return this.nonExposedDatasource;
}

//This does exactly the same as @ConfigurationProperties("com.non.exposed.hikari") but without requiring the exposure of the Datasource in the ctx as @Bean
private <T extends DataSource> T bindHikariProperties(final T instance) {
    return Binder.get(this.environment).bind("com.non.exposed.datasource.hikari", Bindable.ofInstance(instance)).get();
}

Тогда вы можете вызывать свой бин внутренне с помощьюthis.privateHikariDatasource() для использования другими вашими бобами.Большое спасибо @LppEdd!

1 Ответ

2 голосов
/ 19 марта 2019

Поскольку этот DataSource является частным для класса, а класс, содержащий класс , может быть / является в контексте Spring, вы можете иметь @ConfigurationProperties класс

@ConfigurationProperties("com.foo.bar.datasource.hikari")
public class HikariConfiguration { ... }
* 1007.* Который, зарегистрировав его через @EnableConfigurationProperties, доступен для автоматической проводки
@EnableConfigurationProperties(HikariConfiguration.class)
@SpringBootApplication
public class Application { ... }

и, таким образом, может быть автоматически подключен в содержащем классе

@Component
class MyClass {
   private final HikariConfiguration hikariConfiguration;  
   private DataSource springDatasource;

   MyClass(final HikariConfiguration hikariConfiguration) {
      this.hikariConfiguration = hikariConfiguration;
   }

   ...

   private DataSource privateSingletonDataSource() {
      if (Objects.isNull(this.springDatasource)) {
         this.springDatasource = buildDataSource(this.hikariConfiguration);
      }

      return this.springDatasource;
   }
}

buildDataSource будет вручную создайте экземпляр DataSource.
Помните, что вам нужно позаботиться о синхронизации при построении DataSource.


В конечном итоге вы не можете повторно использовать DataSourceProperties,Вы даже не можете расширить его, чтобы изменить префикс свойств.Только один его экземпляр может существовать внутри контекста.
Лучшее, что вы можете сделать, это имитировать то, что делает Spring.

Имея

com.non.exposed.datasource.hikari.url=testUrl
com.non.exposed.datasource.hikari.username=testUsername
com.non.exposed.datasource.hikari.password=testPassword
...

Вы можете определить новый @ConfigurationPropertiesclass

@ConfigurationProperties("com.non.exposed.datasource")
public class NonExposedProperties {
    private final Map<String, String> hikari = new HashMap<>(8);

    public Map<String, String> getHikari() {
        return hikari;
    }
}

Затем выполните автоматическое связывание этого класса свойств в вашем @Configuration / @Component классе.
Следуйте комментариям в коде.

@Configuration
public class CustomConfiguration {
    private final NonExposedProperties nonExposedProperties;
    private DataSource dataSource;

    CustomConfiguration(final NonExposedProperties nonExposedProperties) {
        this.nonExposedProperties= nonExposedProperties;
    }

    public DataSource dataSource() {
        if (Objects.isNull(dataSource)) {
            // Create a standalone instance of DataSourceProperties
            final DataSourceProperties dataSourceProperties = new DataSourceProperties();

            // Use the NonExposedProperties "hikari" Map as properties' source. It will be
            // {
            //    url      -> testUrl
            //    username -> testUsername
            //    password -> testPassword
            //    ... other properties
            // }
            final ConfigurationPropertySource source = new MapConfigurationPropertySource(nonExposedProperties.getHikari());

            // Bind those properties to the DataSourceProperties instance
            final BindResult<DataSourceProperties> binded =
                    new Binder(source).bind(
                            ConfigurationPropertyName.EMPTY,
                            Bindable.ofInstance(dataSourceProperties)
                    );

            // Retrieve the binded instance (it's not a new one, it's the same as before)
            dataSource = binded.get().initializeDataSourceBuilder().build();
        }

        // Return the constructed HikariDataSource
        return dataSource;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...