您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關springboot中application.yml的文件配置是怎樣的,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
springboot最簡便的地方,一是開箱即用,二是配置簡單,配置文件路徑一般在/src/main/resources 下,主要配置有兩種形式,一種是properties文件,一種是springboot官方推薦的yml后綴的文件
使用properties文件springboot配置
#配置內置tomcat啟動端口 server.port=8080 #給程序起個名字 spring.application.name=boot-helloworld
properties文件作為眾多配置文件中的佼佼者,使用比較方便,格式簡單,等號左邊為屬性,右邊為值,可以說是簡單方便
使用yml文件作為springboot配置
#配置內置tomcat啟動端口 server: port: 8080 #應用名稱 spring: application: name: boot-helloworld
yml文件中,有著嚴格的層級關系,以空格或者Tab縮進表示,英文冒號結尾,末尾層級最后空至少一個英文空格,然后填寫該屬性的值,優點在于,層級表示可以簡單的連著寫多個值,例如:
spring: application: name: boot-helloworld #redis連接池配置, 可以換行保持縮進,連著寫 redis: host: localhost port: 6379 password: password timeOut: 5000 maxIdle: 50 maxWaitMillis: 5000 maxTotal: 500
以下摘自 spring-boot-autoconfiguration.jar中的spring-configuration-metadata.json,另外,springboot默認配置都在此包中的spring-autoconfigure-metadata.properties文件中有指定,有需要的同學可以去翻閱,不同springboot版本,默認的屬性有區別
指定項目啟動端口
server: port: 8081
給項目指定名稱
spring: application: name: boot-helloworld
日志級別
#默認情況下springboot使用Logback作為日志框架 #logging.level開頭,指定一個依賴的groupId然后,指定日志級別 logging: level: org.springframeword.web: debug
多個環境下指定啟動使用的配置環境
#只需要在application.properties中設置spring.profiles.active=prod來指定活動的profile即可 #如下表示采用application-test.yml #默認使用default(application.yml),這樣可以區分開發、線上、測試,preview等環境 spring: profiles: active: test
指定項目路徑
#在所有接口訪問路徑之前需要加/boot server: servlet: context-path: /boot
以下代碼僅供演示
1: User.java
/** * 當作一個配置項,簡單處理 * @author Calvin * @date 2019/07/24 */ public class User { /** * ID */ private String id; /** * 名字 */ private String userName; /** * 年齡 */ private Integer age; /** * 性別 */ private String gender; /** * 所使用的操作系統 */ private String systemName; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getSystemName() { return systemName; } public void setSystemName(String systemName) { this.systemName = systemName; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", userName='" + userName + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", systemName='" + systemName + '\'' + '}'; } }
2: application.yml
spring: application: name: boot-helloworld logging: level: org.springframeword.web: debug server: servlet: context-path: /boot # admin年齡的值配置 admin: age: 20
3:ValueController.java
/** * 測試@Value注解的各種方式 * @author Calvin * @date 2019/07/24 */ @RestController @RequestMapping("/value") public class ValueController { /** * ID 采用表達式注解 */ @Value("#{ T(java.util.UUID).randomUUID()}") private String adminId; /** * name 采用值注解獲取一個UUID */ @Value("Calvin") private String adminName; /** * gender 給定一個默認值,如果沒有定義,就采用默認值 */ @Value("${admin.gender: 男}") private String adminGender; /** * 注入yml文件中的admin.age */ @Value("${admin.age}") private Integer adminAge; /** * 采用表達式獲取系統變量 */ @Value("#{systemProperties['os.name']}") private String systemName; /** * 獲取用戶信息 * @return */ @GetMapping("/getUserInfo") public User getAdminInfo(){ User admin = new User(); admin.setId(adminId); admin.setUserName(adminName); admin.setAge(adminAge); admin.setGender(adminGender); admin.setSystemName(systemName); return admin; } }
4:調用結果
springboot配置文件不僅可以使用@Value注解, 還有很多好玩的方式,另一個可以使用@ConfigurationProperties去注入到某個Bean中,具體方法此處不做調研
源碼解讀非常不容易,筆者也是參考了網上很多資源,才撰寫出這部分,希望大家多多指教,此處就不畫圖了,畫圖功底不好
1: 調用鏈
BootApplication.main()
//main方法,程序入口 SpringApplication.run(BootApplication.class, args);
SpringApplication.run():1202
//實例化SpringApplication并且調用run方法 return new SpringApplication(primarySources).run(args);
SpringApplication.run():304
//此方法中實例化Environment ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
SpringApplication.prepareEnvironment():338
//因為我是Web程序,用的是spring-boot-starter-web依賴,所以是StandardServletEnvironment private ConfigurableEnvironment getOrCreateEnvironment() { //省略部分代碼 return new StandardServletEnvironment(); } //因為StandardServletEnviroment extends AbstractEnvironment //而AbstractEnvironment構造器中中調用了customizePropertySources()方法 public AbstractEnvironment() { //模板方法,大家都懂得 customizePropertySources(this.propertySources); }
StandardServletEnvironment.customizePropertySources():54
protected void customizePropertySources(MutablePropertySources propertySources) { //將servletConfigInitParams添加進PropertySource中 propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME)); //將servletContextInitParams添加進PropertySource中 propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)); if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) { propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME)); } //調用AbstractEnvironment.customizePropertySources()方法 super.customizePropertySources(propertySources); }
AbstractEnvironment.customizePropertySources():77
@Override protected void customizePropertySources(MutablePropertySources propertySources) { //添加systemProperties, 添加的是System.getProperties(),是一個Native方法,主要屬性是 //java.runtime.name | java.vm.version等系統配置的屬性 propertySources.addLast( new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); //添加systemEnvironment, 也就是系統環境變量, 其中包含JAVA_HOME等屬性 propertySources.addLast( new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())); }
至此結束,ConfigurableEnvironment對象中添加了四個propertySource,分別為:
[servletConfigInitParams, servletContextInitParams , systemProperties, systemEnvironment]
看完 SpringApplication.prepareEnvironment():338所作的事情, 接著看listeners.environmentPrepared(environment):340,這也是yml文件配置的入口
SpringApplicationRunListeners.environmentPremared
public void environmentPrepared(ConfigurableEnvironment environment) { for (SpringApplicationRunListener listener : this.listeners) { listener.environmentPrepared(environment); } }
這個方法中加載了很多個Listener,每個的調用鏈也非常深,這里簡短點,
SpringApplicationRunListeners.java
environmentPrepared-->
SimpleApplcationEventMulticaster.java
multicastEvent():126&131-->
invokeListener():159-->
doInvokeListener(listener, event) -->
CofigFileApplicationListener.java
onApplicationEvent():-->
addPostProcessors();-->
new Loader(environment, resourceLoader).load():202-->
load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,DocumentConsumer consumer):429-->
前方高能,筆者跟代碼跟的非常之辛苦,廢話少說,ConfigFileApplicationListener.java中核心代碼
ConfigFileApplicationListener.onApplicationEvent()
@Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); } if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent(event); } }
ConfigFileApplicationListener.load()
private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) { if (!StringUtils.hasText(name)) { for (PropertySourceLoader loader : this.propertySourceLoaders) { if (canLoadFileExtension(loader, location)) { load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer); return; } } } Set<String> processed = new HashSet<>(); //遍歷propertySourceLoaders for (PropertySourceLoader loader : this.propertySourceLoaders) { for (String fileExtension : loader.getFileExtensions()) { if (processed.add(fileExtension)) { //尋找配置文件 loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory, consumer); } } } }
this.propertySourceLoaders中有兩個類,都是PropertySourceLoader的實現類,分別是
[ org.springframework.boot.env.PropertiesPropertySourceLoader, org.springframework.boot.env.YamlPropertySourceLoader ]
PropertiesPropertySourceLoader.java
/** *<p> * <li>此類負責加載["properties", "xml"]后綴的配置文件 * <li>loadProerties負責讀取配置文件中的內容 *</p> */ public class PropertiesPropertySourceLoader implements PropertySourceLoader { private static final String XML_FILE_EXTENSION = ".xml"; @Override public String[] getFileExtensions() { return new String[] { "properties", "xml" }; } @Override public List<PropertySource<?>> load(String name, Resource resource) throws IOException { Map<String, ?> properties = loadProperties(resource); if (properties.isEmpty()) { return Collections.emptyList(); } return Collections.singletonList(new OriginTrackedMapPropertySource(name, properties)); } @SuppressWarnings({ "unchecked", "rawtypes" }) private Map<String, ?> loadProperties(Resource resource) throws IOException { String filename = resource.getFilename(); if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) { return (Map) PropertiesLoaderUtils.loadProperties(resource); } return new OriginTrackedPropertiesLoader(resource).load(); } }
YamlPropertySourceLoader.java
/** *<p> * <li>此類負責加載["yml", "yaml"]后綴的配置文件 * <li>load負責讀取配置文件中的內容 *</p> */ public class YamlPropertySourceLoader implements PropertySourceLoader { @Override public String[] getFileExtensions() { return new String[] { "yml", "yaml" }; } @Override public List<PropertySource<?>> load(String name, Resource resource) throws IOException { if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { throw new IllegalStateException( "Attempted to load " + name + " but snakeyaml was not found on the classpath"); } List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load(); if (loaded.isEmpty()) { return Collections.emptyList(); } List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size()); for (int i = 0; i < loaded.size(); i++) { String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : ""; propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber, loaded.get(i))); } return propertySources; } }
至此結束,找到了加載application.yml文件的位置,接著往下跟 會在此方法中加載,具體調用了Yaml類構造器,StreamReader去讀取文件
public List<Map<String, Object>> load() { final List<Map<String, Object>> result = new ArrayList<>(); process((properties, map) -> result.add(getFlattenedMap(map))); return result; }
YamlProcessor.java
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, @Nullable String path) { source.forEach((key, value) -> { if (StringUtils.hasText(path)) { if (key.startsWith("[")) { key = path + key; } else { key = path + '.' + key; } } if (value instanceof String) { result.put(key, value); } else if (value instanceof Map) { // Need a compound key @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) value; buildFlattenedMap(result, map, key); } else if (value instanceof Collection) { // Need a compound key @SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value; if (collection.isEmpty()) { result.put(key, ""); } else { int count = 0; for (Object object : collection) { buildFlattenedMap(result, Collections.singletonMap( "[" + (count++) + "]", object), key); } } } else { result.put(key, (value != null ? value : "")); } }); }
來點廢話,這個加載的調用鏈非常深,六七個類,不少于十幾個方法,有興趣的同學可以研究研究,學習使用的同學請不要過于關注這個,不過讀源碼有助于更好的理解框架,如有不同理解或者文中有誤,歡迎多多指正。
1:簡單解釋springboot常用兩種配置文件
2:基于兩種配置文件,分別做實現
3:@Value注解常用方式
4:yml文件加載源碼解讀
看完上述內容,你們對springboot中application.yml的文件配置是怎樣的有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。