Spring 配置文件可以选择 @PropertySources 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12691812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can @PropertySources be chosen by Spring profile?
提问by Emerson Farrugia
I have a Spring 3.1 @Configurationthat needs a property footo build a bean. The property is defined in defaults.propertiesbut may be overridden by the property in overrides.propertiesif the application has an active overrideSpring profile.
我有一个 Spring 3.1 @Configuration,它需要一个属性foo来构建一个 bean。如果应用程序具有活动的Spring 配置文件defaults.properties,overrides.properties则该属性在 in 中定义,但可能被 in 中的属性覆盖override。
Without the override, the code would look like this, and work...
如果没有覆盖,代码看起来像这样,并且可以工作......
@Configuration
@PropertySource("classpath:defaults.properties")
public class MyConfiguration {
@Autowired
private Environment environment;
@Bean
public Bean bean() {
...
// this.environment.getRequiredProperty("foo");
...
}
}
I would like a @PropertySourcefor classpath:overrides.propertiescontingent on @Profile("overrides"). Does anyone have any ideas on how this could be achieved? Some options I've considered are a duplicate @Configuration, but that would violate DRY, or programmatic manipulation of the ConfigurableEnvironment, but I'm not sure where the environment.getPropertySources.addFirst()call would go.
我想一个@PropertySource用于classpath:overrides.properties对队伍@Profile("overrides")。有没有人对如何实现这一目标有任何想法?我考虑过的一些选项是重复的@Configuration,但这会违反 DRY 或对 的编程操作ConfigurableEnvironment,但我不确定environment.getPropertySources.addFirst()调用会去哪里。
Placing the following in an XML configuration works if I inject the property directly with @Value, but not when I use Environmentand the getRequiredProperty()method.
如果我直接使用 注入属性@Value,则将以下内容放在 XML 配置中有效,但在使用Environment和getRequiredProperty()方法时则无效。
<context:property-placeholder ignore-unresolvable="true" location="classpath:defaults.properties"/>
<beans profile="overrides">
<context:property-placeholder ignore-unresolvable="true" order="0"
location="classpath:overrides.properties"/>
</beans>
Update
更新
If you're trying to do this now, check out Spring Boot's YAML support, particularly the 'Using YAML instead of Properties' section. The profile support there would make this question moot, but there isn't @PropertySourcesupport yet.
如果您现在尝试这样做,请查看 Spring Boot 的YAML 支持,尤其是“使用 YAML 而不是属性”部分。那里的配置文件支持会使这个问题没有实际意义,但尚不@PropertySource支持。
回答by David Harkness
Add the overriding @PropertySourcein a static inner class. Unfortunately, you must specify all property sources together which means creating a "default" profile as the alternative to "override".
@PropertySource在静态内部类中添加覆盖。不幸的是,您必须一起指定所有属性源,这意味着创建一个“默认”配置文件作为“覆盖”的替代方案。
@Configuration
public class MyConfiguration
{
@Configuration
@Profile("default")
@PropertySource("classpath:defaults.properties")
static class Defaults
{ }
@Configuration
@Profile("override")
@PropertySource({"classpath:defaults.properties", "classpath:overrides.properties"})
static class Overrides
{
// nothing needed here if you are only overriding property values
}
@Autowired
private Environment environment;
@Bean
public Bean bean() {
...
// this.environment.getRequiredProperty("foo");
...
}
}
回答by Sebastien Lorber
You can do:
你可以做:
<context:property-placeholder location="classpath:${spring.profiles.active}.properties" />
Edit: if you need something more advanced, you can register your PropertySources on application startup.
编辑:如果您需要更高级的东西,您可以在应用程序启动时注册您的 PropertySources。
web.xml
网页.xml
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.xxx.core.spring.properties.PropertySourcesApplicationContextInitializer</param-value>
</context-param>
file you create:
您创建的文件:
public class PropertySourcesApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(PropertySourcesApplicationContextInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
LOGGER.info("Adding some additional property sources");
String[] profiles = applicationContext.getEnvironment().getActiveProfiles()
// ... Add property sources according to selected spring profile
// (note there already are some property sources registered, system properties etc)
applicationContext.getEnvironment().getPropertySources().addLast(myPropertySource);
}
}
Once you've done it you just need to add in your context:
完成后,您只需要在上下文中添加:
<context:property-placeholder/>
I can't really answer to your question about multiple profiles but I guess you activate them on such an initializer, and you could register the appropriate PropertySource items during profile activations.
我无法真正回答您关于多个配置文件的问题,但我猜您在这样的初始化程序上激活它们,并且您可以在配置文件激活期间注册适当的 PropertySource 项目。
回答by Spille
I suggest, defining two files, where the second is optional with the profile as suffix:
我建议定义两个文件,其中第二个是可选的,以配置文件为后缀:
@Configuration
@PropertySources({
@PropertySource("classpath:/myconfig.properties"),
@PropertySource(value = "classpath:/myconfig-${spring.profiles.active}.properties", ignoreResourceNotFound = true)
})
public class MyConfigurationFile {
@Value("${my.prop1}")
private String prop1;
@Value("${my.prop2}")
private String prop2;
}
回答by whitebrow
In case you need to support multiple profiles you could do something like this:
如果您需要支持多个配置文件,您可以执行以下操作:
@Configuration
public class Config {
@Configuration
@Profile("default")
@PropertySource("classpath:application.properties")
static class DefaultProperties {
}
@Configuration
@Profile("!default")
@PropertySource({"classpath:application.properties", "classpath:application-${spring.profiles.active}.properties"})
static class NonDefaultProperties {
}
}
That way you don't need to define a static configuration class for each profile. Thanks David Harknessfor putting me into the right direction.
这样你就不需要为每个配置文件定义一个静态配置类。感谢David Harkness让我走向正确的方向。
回答by Biju Kunjummen
I can't think of any other way than one you have suggested Emerson, which is to define this bean in a separate @Configurationfile with an @Profileannotation:
除了您建议的 Emerson 之外,我想不出任何其他方式,即在@Configuration带有@Profile注释的单独文件中定义此 bean :
@Configuration
@Profile("override")
@PropertySource("classpath:override.properties")
public class OverriddenConfig {
@Autowired
private Environment environment;
@Bean
public Bean bean() {
//if..
}
}
回答by David Harkness
Note:This answer provides an alternate solution to using properties files with @PropertySource. I went this route because it was too cumbersome trying to work with multiple properties files that may each have overrides while avoiding repetitive code.
注意:此答案提供了将属性文件与@PropertySource. 我走这条路是因为尝试使用多个属性文件太麻烦了,每个属性文件可能都有覆盖,同时避免重复代码。
Create a POJO interface for each related set of properties to define their names and types.
为每个相关的属性集创建一个 POJO 接口来定义它们的名称和类型。
public interface DataSourceProperties
{
String driverClassName();
String url();
String user();
String password();
}
Implement to return the default values.
实现返回默认值。
public class DefaultDataSourceProperties implements DataSourceProperties
{
public String driverClassName() { return "com.mysql.jdbc.Driver"; }
...
}
Subclass for each profile (e.g. development, production) and override any values that differ from the default. This requires a set of mutually-exclusive profiles, but you can easily add "default" as the alternative to "overrides".
每个配置文件(例如开发、生产)的子类并覆盖与默认值不同的任何值。这需要一组互斥的配置文件,但您可以轻松添加“默认”作为“覆盖”的替代方案。
@Profile("production")
@Configuration
public class ProductionDataSourceProperties extends DefaultDataSourceProperties
{
// nothing to override as defaults are for production
}
@Profile("development")
@Configuration
public class DevelopmentDataSourceProperties extends DefaultDataSourceProperties
{
public String user() { return "dev"; }
public String password() { return "dev"; }
}
Finally, autowire the properties configurations into the other configurations that need them. The advantage here is that you don't repeat any @Beancreation code.
最后,将属性配置自动装配到需要它们的其他配置中。这里的优点是您不会重复任何@Bean创建代码。
@Configuration
public class DataSourceConfig
{
@Autowired
private DataSourceProperties properties;
@Bean
public DataSource dataSource() {
BoneCPDataSource source = new BoneCPDataSource();
source.setJdbcUrl(properties.url());
...
return source;
}
}
I am still not convinced I'll stick with this over manually configuring properties files based on the active profiles in a servlet context initializer. My thought was that doing manual configuration would not be as amenable to unit testing, but I'm not so sure now. I really prefer reading properties files to a list of property accessors.
我仍然不相信我会坚持这一点,而不是根据 servlet 上下文初始值设定项中的活动配置文件手动配置属性文件。我的想法是进行手动配置不会适合单元测试,但我现在不太确定。我真的更喜欢阅读属性文件而不是属性访问器列表。

