我想从@ConfigurationProperties
的便利设施中受益,而无需将bean暴露在我的上下文中。这不是@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()
在内部调用您的bean,以供其他bean使用。
非常感谢@LppEdd!
答案 0 :(得分:2)
由于该DataSource
是类的私有对象,并且包含类可以在Spring上下文中存在,所以可以有一个@ConfigurationProperties
类
@ConfigurationProperties("com.foo.bar.datasource.hikari")
public class HikariConfiguration { ... }
通过@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
...
您可以定义一个新的@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
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;
}
}