Spring Boot Application

spring boot默認已經配置了不少環境變量,例如,tomcat的默認端口是8080,項目的contextpath是「/」等等,spring boot容許你自定義一個application.properties文件,而後放在如下的地方,來重寫spring boot的環境變量web

spring對配置application.properties的加載過程:spring

  1. 服務啓動調用:SpringApplication.run
  2. 建立默認的環境參數:ConfigurableEnvironment
  3. 觸發事件:ApplicationEnvironmentPreparedEvent
  4. 完成加載

整個過程主要使用spring boot 內置的ConfigFileApplicationListener監聽器監聽ApplicationEnvironmentPreparedEvent事件完成對application.properties加載以及設置。tomcat


下面咱們來跟蹤源碼,看下spring boot是怎樣完成對application.properties文件的加載app

  • SpringApplication 入口 run:
  1.  
    public ConfigurableApplicationContext run(String... args) {
  2.  
    //無關的代碼暫略
  3.  
    .......
  4.  
    ConfigurableApplicationContext context =  null;
  5.  
    FailureAnalyzers analyzers =  null;
  6.  
    configureHeadlessProperty();
  7.  
    //獲取執行監聽器實例
  8.  
    SpringApplicationRunListeners listeners = getRunListeners(args);
  9.  
    ........
  10.  
    //建立全局系統參數實例
  11.  
    ApplicationArguments applicationArguments =  new DefaultApplicationArguments(
  12.  
    args);
  13.  
    //建立 ConfigurableEnvironment 並觸發ApplicationEnvironmentPreparedEvent事件
  14.  
    //加載配置的核心地方,spring啓動首要作的事情
  15.  
    ConfigurableEnvironment environment = prepareEnvironment(listeners,
  16.  
    applicationArguments);
  17.  
    .........
  18.  
    }

prepareEnvironment方法less

  1.  
    private ConfigurableEnvironment prepareEnvironment(
  2.  
    SpringApplicationRunListeners listeners,
  3.  
    ApplicationArguments applicationArguments) {
  4.  
    // Create and configure the environment
  5.  
    //建立一個配置環境信息,當是web環境時建立StandardServletEnvironment實例,非web環境時建立StandardEnvironment實例
  6.  
    ConfigurableEnvironment environment = getOrCreateEnvironment();
  7.  
    configureEnvironment(environment, applicationArguments.getSourceArgs());
  8.  
    //核心事件觸發方法,此方法執行後會執行全部監聽ApplicationEnvironmentPreparedEvent事件的監聽器,這裏咱們是跟蹤application.properties文件的加載,就查看ConfigFileApplicationListener監聽器都作了什麼工做
  9.  
    listeners.environmentPrepared(environment);
  10.  
    if (!this.webEnvironment) {
  11.  
    environment =  new EnvironmentConverter(getClassLoader())
  12.  
    .convertToStandardEnvironmentIfNecessary(environment);
  13.  
    }
  14.  
    return environment;
  15.  
    }
  • ConfigFileApplicationListener:
  1.  
    public void onApplicationEvent(ApplicationEvent event) {
  2.  
    //今後處能夠看到當事件爲ApplicationEnvironmentPreparedEvent時,執行onApplicationEnvironmentPreparedEvent方法
  3.  
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
  4.  
    onApplicationEnvironmentPreparedEvent(
  5.  
    (ApplicationEnvironmentPreparedEvent)  event);
  6.  
    }
  7.  
    if (event instanceof ApplicationPreparedEvent) {
  8.  
    onApplicationPreparedEvent( event);
  9.  
    }
  10.  
    }

onApplicationEnvironmentPreparedEventdom

  1.  
    private void onApplicationEnvironmentPreparedEvent(
  2.  
    ApplicationEnvironmentPreparedEvent  event) {
  3.  
    //此處經過SpringFactoriesLoader加載EnvironmentPostProcessor全部擴展
  4.  
    List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
  5.  
    //由於此監聽器一樣是EnvironmentPostProcessor的擴展實例,因此在此處將本身加入集合
  6.  
    postProcessors. add(this);
  7.  
    AnnotationAwareOrderComparator.sort(postProcessors);
  8.  
    //遍歷全部的EnvironmentPostProcessor擴展調用postProcessEnvironment
  9.  
    //固然咱們跟蹤是application.properties因此主要查看當前實例的postProcessEnvironment方法
  10.  
    for (EnvironmentPostProcessor postProcessor : postProcessors) {
  11.  
    postProcessor.postProcessEnvironment( event.getEnvironment(),
  12.  
    event.getSpringApplication());
  13.  
    }
  14.  
    }

postProcessEnvironmentide

  1.  
    @Override
  2.  
    public void postProcessEnvironment(ConfigurableEnvironment environment,
  3.  
    SpringApplication application) {
  4.  
    //此處添加配置信息到environment實例中,此方法完成後就將application.properties加載到環境信息中
  5.  
    addPropertySources(environment, application.getResourceLoader());
  6.  
    configureIgnoreBeanInfo(environment);
  7.  
    bindToSpringApplication(environment, application);
  8.  
    }

addPropertySources工具

  1.  
    protected void addPropertySources(ConfigurableEnvironment environment,
  2.  
    ResourceLoader resourceLoader) {
  3.  
    //這裏先添加一個Random名稱的資源到環境信息中
  4.  
    RandomValuePropertySource.addToEnvironment(environment);
  5.  
    //經過Loader加載application.properties並將信息存入環境信息中
  6.  
    new Loader(environment, resourceLoader).load();
  7.  
    }

loadpost

  1.  
    public void load() {
  2.  
    //建立一個資源加載器,spring boot默認支持PropertiesPropertySourceLoader,YamlPropertySourceLoader兩種配置文件的加載
  3.  
    this.propertiesLoader = new PropertySourcesLoader();
  4.  
    this.activatedProfiles = false;
  5.  
    //加載配置profile信息,默認爲default
  6.  
    ..........此處省略
  7.  
    while (!this.profiles.isEmpty()) {
  8.  
    Profile profile =  this.profiles.poll();
  9.  
    //遍歷全部查詢路徑,默認路徑有:classpath:/,classpath:/config/,file:./,file:./config/
  10.  
    for (String location : getSearchLocations()) {
  11.  
    //這裏不單單是加載application.properties,當搜索路徑不是以/結束,默認認爲是文件名已存在的路徑
  12.  
    if (!location.endsWith("/")) {
  13.  
    // location is a filename already, so don't search for more
  14.  
    // filenames
  15.  
    load(location,  null, profile);
  16.  
    }
  17.  
    else {
  18.  
    //遍歷要加載的文件名集合,默認爲application
  19.  
    for (String name : getSearchNames()) {
  20.  
    load(location, name, profile);
  21.  
    }
  22.  
    }
  23.  
    }
  24.  
    this.processedProfiles.add(profile);
  25.  
    }
  26.  
     
  27.  
    //將加載完成的配置信息所有保存到環境信息中共享
  28.  
    addConfigurationProperties( this.propertiesLoader.getPropertySources());
  29.  
    }

loadui

  1.  
    private void load(String location, String name, Profile profile) {
  2.  
    //此處根據profile組裝加載的文件名稱以及資源所放置的組信息
  3.  
    String  group = "profile=" + (profile == null ? "" : profile);
  4.  
    if (!StringUtils.hasText(name)) {
  5.  
    // Try to load directly from the location
  6.  
    loadIntoGroup( group, location, profile);
  7.  
    }
  8.  
    else {
  9.  
     
  10.  
    // Also try the profile-specific section (if any) of the normal file
  11.  
    loadIntoGroup( group, location + name + "." + ext, profile);
  12.  
    }
  13.  
    }
  14.  
    }

loadIntoGroup

  1.  
    private PropertySource<?> doLoadIntoGroup( String identifier, String location,
  2.  
    Profile profile) throws IOException {
  3.  
    Resource resource =  this.resourceLoader.getResource(location);
  4.  
    PropertySource<?> propertySource =  null;
  5.  
    if (resource != null && resource.exists()) {
  6.  
    String name = "applicationConfig: [" + location + "]";
  7.  
    String group = "applicationConfig: [" + identifier + "]";
  8.  
    //資源加載核心方法,此處有兩個實現,當後綴爲,xml或者properties調用PropertiesPropertySourceLoader
  9.  
    //當後綴爲yml或者yaml時,調用YamlPropertySourceLoader
  10.  
     
  11.  
    propertySource =  this.propertiesLoader.load(resource,
  12.  
    }
  13.  
     
  14.  
    return propertySource;
  15.  
    }
  • PropertiesPropertySourceLoader:
  1.  
    @Override
  2.  
    public PropertySource<?> load(String name, Resource resource, String profile)
  3.  
    throws IOException {
  4.  
    if (profile == null) {
  5.  
    //此處調用PropertiesLoaderUtils工具類加載本地文件
  6.  
    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  7.  
    if (!properties.isEmpty()) {
  8.  
    return new PropertiesPropertySource(name, properties);
  9.  
    }
  10.  
    }
  11.  
    return null;
  12.  
    }

到此application.properties就真正的加載並共享到環境信息中,供系統其它地方調用

相關文章
相關標籤/搜索