如何在Spring Boot中優(yōu)雅地加載配置?這些方法你必須掌握!
環(huán)境:SpringBoot3.4.3
1. 簡介
當Spring Boot啟動時,它會按照特定的順序搜索配置文件,如下配置文件加載順序的說明:
- 首先,它會查找bootstrap.properties或bootstrap.yml文件。這些文件具有最高優(yōu)先級,就像我們的“晨間例行事務(wù)”一樣,總是首先考慮。
- 接下來,它會搜索application.properties或application.yml文件。這些是項目的“日常配置”,處理大多數(shù)場景。
- 如果配置了spring.profiles,它還會加載相應的環(huán)境特定配置文件,如application-dev.properties。這就像為不同場合準備不同的著裝一樣。
圖片
請注意:bootstrap配置文件的加載是在Spring Cloud環(huán)境下。
如下是Spring Boot官方對配置文件加載順序的說明:
圖片
接下來,我們將詳細的介紹有關(guān)Spring Boot配置文件加載的詳細內(nèi)容。
2. 實戰(zhàn)案例
2.1 @Value注解
當我們只需要從配置文件中獲取一個簡單的值,而@Value注解可以輕松地實現(xiàn)這一點。
pack:
title: xxxooo
使用@Value注入配置值
@Service
public class TestService {
@Value("${pack.title}")
private String title ;
// ...
}
但請注意,如果你的配置文件中沒有配置pack.title,那么服務(wù)將無法正確啟動。所以,我們應該考慮如下方式配置:
@Value("${pack.title:default_title}")
private String title ;
當配置文件沒有配置pack.title時,將使用這里冒號后面的默認值: default_title。
關(guān)于@Value注解更多的用法,請查看下面這篇文章:
SpringBoot @Value注解這些高級玩法用過嗎?
2.2 @ConfigurationProperties注解
在某些場景下,@Value注解無法滿足我們的所有需求,比如當參數(shù)配置是一個對象或數(shù)組時。在這種情況下,使用@ConfigurationProperties是一個更好的選擇。
pack:
version: 1.0.2
title: xxxooo
配置對象定義如下:
@Component
@ConfigurationProperties(prefix = "pack")
public class App {
private String title ;
private String version ;
// getters, setters
}
通過這里配置的前綴 prefix = "pack" ,自動于類中的屬性進行映射。
Map & List集合映射
@Component
@ConfigurationProperties(prefix = "pack")
public class App {
private Map<String, Object> params = new HashMap<>() ;
private List<String> addresses = new ArrayList<>() ;
}
配置文件定義如下:
pack:
params:
version: 1.0.0
title: xxxooo
addresses:
- xxx
- ooo
請注意,Map集合的value與List都可以是任意其它的對象類型。
關(guān)于@ConfigurationProperties更多高級用法請查看下面文章:
進階!@ConfigurationProperties注解高級用法你知道嗎?
2.3 @PropertySource注解
有時,我們希望將不同模塊的配置分開,比如將數(shù)據(jù)庫配置放在一個文件中,緩存配置放在另一個文件中,以便更加清晰。這時,@PropertySource注解就派上了用場。在資源目錄中創(chuàng)建配置文件,db.properties,內(nèi)容如下:
db.user=root
db.password=123456
db.url=xxxx
使用@PropertySource加載配置文件
@Component
@PropertySource(value = {"db.properties"})
public class DbProperties {
}
value是數(shù)組,可以定義多個配置文件。
請注意,@PropertySource默認是不支持yaml文件的加載。如果需要加載yaml或其它格式的文件還需要自定義PropertySourceFactory,然后通過factory屬性進行定義。
關(guān)于@PropertySource更多高級用法,請查看下面文章:
我不信!你會用@PropertySource注解?高級法
2.4 EnvironmentPostProcessor
如果你需要更早或更靈活的配置文件加載方式,比如根據(jù)環(huán)境動態(tài)加載不同的配置,你可以通過自定義EnvironmentPostProcessor接口。
public class PackEnvironmentPostProcessor implements EnvironmentPostProcessor {
final String[] profiles = {
"test.properties","bussiness.properties", "pack.yml"
};
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
for (String profile : profiles) {
Resource resource = new ClassPathResource(profile);
environment.getPropertySources().addLast(loadProfiles(resource));
}
}
private PropertySource<?> loadProfiles(Resource resource) {
if (!resource.exists()) {
throw new IllegalArgumentException("Resource " + resource + " does not exist");
}
if(resource.getFilename().contains(".yml")){
return loadYaml(resource);
} else {
return loadProperty(resource);
}
}
// 加載屬性文件
private PropertySource loadProperty(Resource resource){
try {
Properties properties = new Properties();
properties.load(resource.getInputStream());
return new PropertiesPropertySource(resource.getFilename(), properties);
}
}
// 加載yaml配置文件
private PropertySource loadYaml(Resource resource){
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource);
Properties properties = factory.getObject();
return new PropertiesPropertySource(resource.getFilename(), properties);
}
}
}
這里我們不能將其定義為bean,需要通過如下的方式進行配置:
META-INF/spring.factories
org.springframework.boot.env.Envirnotallow=\
com.pack.env.PackEnvironmentPostProcessor
這樣配置后,容器在啟動時初始化Environment時會自動的讀取配置文件中的EnvironmentPostProcessor。
2.5 其它配置文件加載方式
我們還可以通過如下的方式加載配置文件:
@Configuration
public class ConfigYaml {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("pack.yml"));
configurer.setProperties(yaml.getObject()) ;
return configurer;
}
}
setResources方法可以定義多個Resource對象。
你還可以通過啟動參數(shù)設(shè)置配置屬性信息,詳細查看下面的鏈接加載JSON數(shù)據(jù)(不僅是JSON,其它key/value都可以進行啟動參數(shù)配置:--xxx=ooo)