我想从@ConfigurationProperties一流的设施中受益,而无需将bean暴露在我的上下文中。这不是问题@Primaries之类的,我根本无法将另一个暴露Datasource在上下文中。如何实现以下目标?
@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(); }
然后,您可以在内部调用Bean,this.privateHikariDatasource()以供其他Bean使用。非常感谢@LppEdd!
this.privateHikariDatasource()
由于这DataSource是类的私有内容,并且包含类的内容 可以 在Spring上下文中,因此您可以拥有一个@ConfigurationProperties类
DataSource
@ConfigurationProperties("com.foo.bar.datasource.hikari") public class HikariConfiguration { ... }
通过进行注册@EnableConfigurationProperties,可用于自动装配
@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。
buildDataSource
最后的回应是您不能重复使用DataSourceProperties。您甚至无法扩展它来更改属性的前缀。在上下文中只能存在一个实例。 您可以做的最好的事情就是模仿Spring的工作。
DataSourceProperties
有
com.non.exposed.datasource.hikari.url=testUrl com.non.exposed.datasource.hikari.username=testUsername com.non.exposed.datasource.hikari.password=testPassword ...
您可以定义一个新@ConfigurationProperties类
@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
@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; } }