Java Spring引导和多个外部配置文件
我想从类路径加载多个属性文件。Java Spring引导和多个外部配置文件,java,spring,config,spring-boot,Java,Spring,Config,Spring Boot,我想从类路径加载多个属性文件。/src/main/resources下有一个默认设置,它是myapp.jar的一部分。我的springcontext希望文件位于类路径上。i、 e <util:properties id="Job1Props" location="classpath:job1.properties"></util:properties> <util:properties id="Job2Props" location="classp
/src/main/resources
下有一个默认设置,它是myapp.jar
的一部分。我的springcontext
希望文件位于类路径上。i、 e
<util:properties id="Job1Props"
location="classpath:job1.properties"></util:properties>
<util:properties id="Job2Props"
location="classpath:job2.properties"></util:properties>
我将我的applicationcontext
更改为
<util:properties id="Job2Props"
location="{app.config.location}/job2.properties"></util:properties>
我真的不想使用上面的解决方法,让spring覆盖类路径上的所有外部配置文件,就像它对应用程序.properties
文件所做的那样。更新:
因为spring.config.location的行为现在覆盖了默认值,而不是添加到默认值中。您需要使用spring.config.additional location
来保持默认值。这是从1.x到2.x的行为变化
使用Spring Boot时,按以下顺序加载属性(请参阅《Spring Boot参考指南》中的)
@Value(${myprop})时,
以相反的顺序进行解析(从9开始)
要添加不同的文件,可以使用spring.config.location
properties,它采用逗号分隔的属性文件或文件位置(目录)列表
上面的一个将添加一个目录,可供application.properties
文件参考
-Dspring.config.location=classpath:job1.properties,classpath:job2.properties
这将向加载的文件中添加2个属性文件
默认配置文件和位置在附加指定的spring.config.location
文件之前加载,这意味着后者将始终覆盖在早期文件中设置的属性。(另请参见《spring引导参考指南》)
如果spring.config.location
包含目录(与文件相反),则它们应以/(结尾,并在加载之前附加从spring.config.name
生成的名称)。无论spring.config.location
的值如何,始终使用默认搜索路径classpath:,classpath:/config,file:,file:config/
。这样,您就可以在application.properties
中为应用程序设置默认值(或使用spring.config.name
选择的任何其他基本名称)并在运行时使用不同的文件覆盖它,保留默认值
看看PropertyPlaceHolderConfigure,我发现它比注释更易于使用 e、 g
@配置
公共类属性配置{
@豆子
公共属性PlaceHolderConfigurer属性(){
final PropertyPlaceHolderConfigure ppc=新的PropertyPlaceHolderConfigure();
//ppc.setIgnoreUnsolvablePlaceholders(true);
ppc.setIgnoreResourceNotFound(true);
最终列表resourceLst=newarraylist();
添加(新类路径资源(“myapp_base.properties”);
add(新文件系统资源(“/etc/myapp/overriding.property”);
添加(新类路径资源(“myapp_test.properties”);
resourceLst.add(新类路径资源(“myapp_developer_overrides.properties”);//用于开发人员调试。
ppc.setLocations(resourceLst.toArray(新资源[]{}));
返回ppc;
}
我刚刚遇到了与此类似的问题,并最终找到了原因:application.properties文件的所有权和rwx属性错误。因此,当tomcat启动时,application.properties文件位于正确的位置,但由另一个用户拥有:
$ chmod 766 application.properties
$ chown tomcat application.properties
我也有同样的问题,我希望能够在启动时用外部文件覆盖内部配置文件,类似于Spring Boot application.properties检测。 在我的例子中,它是一个user.properties文件,存储我的应用程序用户 我的要求: 从以下位置加载文件(按此顺序)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Properties;
import static java.util.Arrays.stream;
@Configuration
public class PropertiesConfig {
private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
private final static String PROPERTIES_FILENAME = "user.properties";
@Value("${properties.location:}")
private String propertiesLocation;
@Bean
Properties userProperties() throws IOException {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(PROPERTIES_FILENAME),
new PathResource("config/" + PROPERTIES_FILENAME),
new PathResource(PROPERTIES_FILENAME),
new PathResource(getCustomPath())
};
// Find the last existing properties location to emulate spring boot application.properties discovery
final Resource propertiesResource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties userProperties = new Properties();
userProperties.load(propertiesResource.getInputStream());
LOG.info("Using {} as user resource", propertiesResource);
return userProperties;
}
private String getCustomPath() {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
}
}
现在应用程序使用类路径资源,但也会检查其他给定位置的资源。将拾取并使用存在的最后一个资源。
我可以用java-jar myapp.jar--properties.location=/directory/myproperties.properties启动我的应用程序,以使用浮动我的船的属性位置
这里有一个重要的细节:使用空字符串作为@value注释中properties.location的默认值,以避免在未设置属性时出错
properties.location的约定是:将属性文件的目录或路径用作properties.location
如果您只想覆盖特定的属性,那么可以将带有setIgnoreResourceNotFound(true)的PropertiesFactoryBean与设置为位置的资源数组一起使用
我确信这个解决方案可以扩展到处理多个文件
编辑
这里是我的多文件解决方案:)像以前一样,这可以与PropertiesFactoryBean结合使用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;
@Configuration
class PropertiesConfig {
private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};
@Value("${properties.location:}")
private String propertiesLocation;
@Bean
Map<String, Properties> myProperties() {
return stream(PROPERTIES_FILENAMES)
.collect(toMap(filename -> filename, this::loadProperties));
}
private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(filename),
new PathResource("config/" + filename),
new PathResource(filename),
new PathResource(getCustomPath(filename))
};
final Resource resource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties properties = new Properties();
try {
properties.load(resource.getInputStream());
} catch(final IOException exception) {
throw new RuntimeException(exception);
}
LOG.info("Using {} as user resource", resource);
return properties;
}
private String getCustomPath(final String filename) {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
}
}
import org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.beans.factory.annotation.Value;
导入org.springframework.context.annotation.Bean;
重要的
@Configuration
public class PropertiesConfiguration {
@Bean
public PropertyPlaceholderConfigurer properties() {
final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
// ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.setIgnoreResourceNotFound(true);
final List<Resource> resourceLst = new ArrayList<Resource>();
resourceLst.add(new ClassPathResource("myapp_base.properties"));
resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
resourceLst.add(new ClassPathResource("myapp_test.properties"));
resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.
ppc.setLocations(resourceLst.toArray(new Resource[]{}));
return ppc;
}
$ chmod 766 application.properties
$ chown tomcat application.properties
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Properties;
import static java.util.Arrays.stream;
@Configuration
public class PropertiesConfig {
private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
private final static String PROPERTIES_FILENAME = "user.properties";
@Value("${properties.location:}")
private String propertiesLocation;
@Bean
Properties userProperties() throws IOException {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(PROPERTIES_FILENAME),
new PathResource("config/" + PROPERTIES_FILENAME),
new PathResource(PROPERTIES_FILENAME),
new PathResource(getCustomPath())
};
// Find the last existing properties location to emulate spring boot application.properties discovery
final Resource propertiesResource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties userProperties = new Properties();
userProperties.load(propertiesResource.getInputStream());
LOG.info("Using {} as user resource", propertiesResource);
return userProperties;
}
private String getCustomPath() {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;
@Configuration
class PropertiesConfig {
private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};
@Value("${properties.location:}")
private String propertiesLocation;
@Bean
Map<String, Properties> myProperties() {
return stream(PROPERTIES_FILENAMES)
.collect(toMap(filename -> filename, this::loadProperties));
}
private Properties loadProperties(final String filename) {
final Resource[] possiblePropertiesResources = {
new ClassPathResource(filename),
new PathResource("config/" + filename),
new PathResource(filename),
new PathResource(getCustomPath(filename))
};
final Resource resource = stream(possiblePropertiesResources)
.filter(Resource::exists)
.reduce((previous, current) -> current)
.get();
final Properties properties = new Properties();
try {
properties.load(resource.getInputStream());
} catch(final IOException exception) {
throw new RuntimeException(exception);
}
LOG.info("Using {} as user resource", resource);
return properties;
}
private String getCustomPath(final String filename) {
return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
}
}
@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {
@Autowired
Environment env;
@Bean
public boolean test() {
System.out.println(env.getProperty("test.one"));
return true;
}
}
test.one = 1234
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(testApplication.class, args);
}
}
spring.profiles.active = one
@Value("${test.one}")
String str;
@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{
@Value("${jdbc.host}")
private String jdbcHostName;
}
}
java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties
set spring.profiles.active=dev
set spring.profiles.active=default
spring.profiles.active=local
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone
spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672
rabbitmq.publish=true
mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
@RunWith(SpringRunner)
@SpringBootTest(classes = [ TestConfiguration, MyApplication ],
properties = [
"spring.config.name=application-MyTest_LowerImportance,application-MyTest_MostImportant"
,"debug=true", "trace=true"
]
)
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_MostImportant.properties' (file:./config/application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_MostImportant.xml' (file:./config/application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_MostImportant.yml' (file:./config/application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_MostImportant.yaml' (file:./config/application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_LowerImportance.properties' (file:./config/application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_LowerImportance.xml' (file:./config/application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_LowerImportance.yml' (file:./config/application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_LowerImportance.yaml' (file:./config/application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_MostImportant.properties' (file:./application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_MostImportant.xml' (file:./application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_MostImportant.yml' (file:./application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_MostImportant.yaml' (file:./application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_LowerImportance.properties' (file:./application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_LowerImportance.xml' (file:./application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_LowerImportance.yml' (file:./application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./application-MyTest_LowerImportance.yaml' (file:./application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_MostImportant.xml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.xml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_MostImportant.xml' resource not found
DEBUG 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_MostImportant.yml' (classpath:/application-MyTest_MostImportant.yml)
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_LowerImportance.xml' resource not found
DEBUG 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_LowerImportance.yml' (classpath:/application-MyTest_LowerImportance.yml)
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'classpath:/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Skipped config file 'file:./config/application-MyTest_MostImportant-test.properties' (file:./config/application-MyTest_MostImportant-test.properties) resource not found
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties
-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties
application:
properties:
locations: "classpath*:/**/*-dev.yml"
@Configuration
public class PropertiesConfig {
private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
@Value("${application.properties.locations}")
private String[] locations;
@Autowired
private ResourceLoader rl;
@Bean
Map<String, Properties> myProperties() {
return stream(locations)
.collect(toMap(filename -> filename, this::loadProperties));
}
private Properties loadProperties(final String filename) {
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
final Properties properties = new Properties();
stream(possiblePropertiesResources)
.filter(Resource::exists)
.map(resource1 -> {
try {
return loader.load(resource1.getFilename(), resource1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).flatMap(l -> l.stream())
.forEach(propertySource -> {
Map source = ((MapPropertySource) propertySource).getSource();
properties.putAll(source);
});
return properties;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
config
- application.yml
- application-dev.yml
- application-prod.yml
management
- management-dev.yml
- management-prod.yml
@Component
public class PropertiesConfigurer extends PropertySourcesPlaceholderConfigurer
implements EnvironmentAware, InitializingBean {
private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfigurer.class);
private String[] locations;
@Autowired
private ResourceLoader rl;
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
// save off Environment for later use
this.environment = environment;
super.setEnvironment(environment);
}
@Override
public void afterPropertiesSet() throws Exception {
// Copy property sources to Environment
MutablePropertySources envPropSources = ((ConfigurableEnvironment) environment).getPropertySources();
envPropSources.forEach(propertySource -> {
if (propertySource.containsProperty("application.properties.locations")) {
locations = ((String) propertySource.getProperty("application.properties.locations")).split(",");
stream(locations).forEach(filename -> loadProperties(filename).forEach(source ->{
envPropSources.addFirst(source);
}));
}
});
}
private List<PropertySource> loadProperties(final String filename) {
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
final Properties properties = new Properties();
return stream(possiblePropertiesResources)
.filter(Resource::exists)
.map(resource1 -> {
try {
return loader.load(resource1.getFilename(), resource1);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).flatMap(l -> l.stream())
.collect(Collectors.toList());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
java -jar yourApp.jar --spring.profiles.active="override" --spring.config.location="file:/tmp/,classpath:/"
java -jar yourApp.jar --spring.profiles.active="override"