除了标准的"app.datasource.alternate"
(DataSourceProperties
)之外,我还希望设置一些自定义数据源属性("spring.datasource"
)。
这两个数据源没有竞争(即
app.datasource.alternate
属性不能替代spring.datasource
属性),应该在默认的应用程序属性中并存。
我希望这样的事情可以工作:
@ConfigurationProperties("app.datasource.alternate")
public class AlternateDataSourceProperties extends DataSourceProperties {}
但是,当我在Yaml中定义属性时:
app:
datasource:
alternate:
schema-username: TEST
并运行我的测试:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE)
@EnableConfigurationProperties({AlternateDataSourceProperties.class})
public class AlternateDataSourcePropertiesTest {
@Autowired
// @Qualifier("alternateDataSourceProperties")
private AlternateDataSourceProperties props;
@Test
public void propertiesAreInjected() {
assertThat(props.getSchemaUsername()).isEqualTo("TEST");
}
}
尝试在NoUniqueBeanDefinitionException
中创建datasource
bean时,程序失败,并显示DataSourceConfiguration.Tomcat
:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Tomcat.class]: Unsatisfied dependency expressed through method 'dataSource' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' available: expected single matching bean but found 2: app.datasource.alternate-com.example.config.AlternateDataSourceProperties,spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:467)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' available: \
expected single matching bean but found 2: \
app.datasource.alternate-com.example.config.AlternateDataSourceProperties \
,spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 66 more
我不想重写一个已经存在的整个属性类,我只需要在不同前缀下的另外一组属性即可。在Spring Boot中有可能吗?
我正在使用Spring Boot 1.5.X
从@Prashant的回答中得到启发,我尝试创建一个附加的配置文件并向其注入以下内容:@PropertySource("classpath:config/alternate-ds.yml")
# alternate-ds.yml
app:
datasource:
alternate:
schema-username: TEST
# AlternateDataSourceProperties.java
@ConfigurationProperties("app.datasource.alternate")
@PropertySource("classpath:config/alternate-ds.yml")
public class AlternateDataSourceProperties extends DataSourceProperties {}
我仍然得到NoUniqueBeanDefinitionException
,因为现在仍然存在竞争的bean资源。有没有一种方法可以指定不应该自动接线的Bean?
答案 0 :(得分:0)
我的方法是:
public class WebApplication {
private static final String CONFIGURATION_FILE_NAME_KEY = "spring.config.name";
private static final String CONFIGURATION_FILE_NAME_VALUE = new StringJoiner(",")
.add("application")
.add("aurora_web")
.toString();
private static final String CONFIGURATION_FILE_NAME_PROPERTY = MessageFormat.format("{0}:{1}", CONFIGURATION_FILE_NAME_KEY, CONFIGURATION_FILE_NAME_VALUE);
public static void main(String[] args) {
new SpringApplicationBuilder(WebApplication.class)
.properties(CONFIGURATION_FILE_NAME_PROPERTY)
.build()
.run(args);
}
Spring允许通过spring.config.name
配置属性文件名。这可以用来允许使用自定义文件名代替默认的application.[property|yml]
。您可以使用覆盖数据源配置的值来创建自己的属性文件,Spring会为您选择该文件。您可以使用@Value()
访问这些属性,或者如果您已从spring的属性中覆盖默认键值,则将从该文件中选择新的键值。
您可以参考following official documentation。
答案 1 :(得分:0)
根据@Prashant的回答,我提出了一个解决方案。该解决方案具有一定的侵入性,因为它重新定义了现有的属性bean,因此可能很危险,但是
@SpringBootTest
似乎可以接受。对我来说,最佳解决方案是以某种方式声明自定义bean不应该由自动装配拾取,我尝试将
autowire = Autowire.NO
参数添加到自定义属性集的@Bean
批注中,但这仍然给出NoUniqueBeanDefinitionException
。
问题在于,由于我在应用程序上下文中添加了DataSourceProperties
类的其他实例,因此在库代码中引用spring时不知道要注入哪个DataSourceProperties
。我想出了一个权宜之计,就是将原始属性定义重新创建为以@Bean
注释的自定义@Primary
,这样我的自定义DataSourceProperties
Bean就不会产生歧义。
当我需要特殊的数据源属性时,我使用@Qualifier("alternateDataSourceProperties")
来引用正确的集合。
Configuration类如下:
@Configuration
public class AlternateDataSourcePropertiesConfiguration {
@Bean
@ConfigurationProperties("app.datasource.alternate")
public DataSourceProperties alternateDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
}
我对它们进行了如下测试:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE, properties={"app.datasource.alternate.schema-username=TEST",
"app.datasource.alternate.username=SOMETHING"})
@ActiveProfiles("test") // there is a default test datasource configured in application-test.properties so I can test that primary configuration is unaffected. i.e. I have a H2 datasource configured here with username 'sa'
public class AlternateDataSourcePropertiesConfigurationTest {
@Autowired
@Qualifier("alternateDataSourceProperties")
private DataSourceProperties alternateDataSourceProperties;
@Autowired
private DataSourceProperties primaryDataSourceProperties;
@Test
public void propertiesAreInjected() {
assertThat(alternateDataSourceProperties.getSchemaUsername()).isEqualTo("TEST");
}
@Test
public void propertiesDontOverridePrimary() {
assertThat(alternateDataSourceProperties.getUsername()).isEqualTo("SOMETHING");
assertThat(primaryDataSourceProperties.getUsername()).isEqualTo("sa");
}
}