我希望受益于 @ConfigurationProperties
出色的设施,而不需要将 bean 暴露到我的上下文中。这不是@Primaries之类的问题,我根本无法将另一个数据源公开到上下文中。我怎样才能实现以下目标?
@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!
最佳答案
由于这个DataSource
对于类来说是私有(private)的,并且包含类可以/是在Spring上下文中,所以你可以有一个@ConfigurationProperties
类
@ConfigurationProperties("com.foo.bar.datasource.hikari")
public class HikariConfiguration { ... }
通过@EnableConfigurationProperties
注册它,可用于 Autowiring
@EnableConfigurationProperties(HikariConfiguration.class)
@SpringBootApplication
public class Application { ... }
因此可以在包含类中 Autowiring
@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
类中 Autowiring 此属性类。
遵循代码中的注释。
@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;
}
}
关于java - 在非托管 @Bean 上使用 @ConfigurationProperties,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55248571/