java - 在非托管 @Bean 上使用 @ConfigurationProperties

标签 java spring spring-boot

我希望受益于 @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/

相关文章:

java在mysql中插入特殊字符

java - 通过 SSL 从 Spring Cloud Config 获取配置

java - 如何从 Do While 封闭开关中的 Integer ArrayList 返回平均值

java - 使用 curl 和 java okhttp 调用简单的 GET 请求时,我得到了不同的结果

java - 在 Grails (Groovy) 和 Java 类之间传递域类的最佳实践?

java - Gradle:依赖顺序如何产生影响?

java - JPA 检查查询是否为空

java - 在java中使用静态类时

java - Spring Cloud Binder : mitigating cost of double bootstrap

java - IBM Redis 数据库 + Spring boot