qiuyadong's Homepage

SpringBoot的environment分析


思往事,惜流芳。易成伤。拟歌先敛,欲笑还颦,最断人肠。

SpringBoot的environment分析

Environment就是环境,是springboot运行的环境信息,简单理解为获取系统配置信息的对象;

那么这些配置信息可以从本地加载也可以从远程获取;

这里分析SpringBoot启动时加载配置设置环境信息的流程;

启动流程

  • 启动

    //启动时可以配置命令行参数,包装成ApplicationArguments
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
    //具体初始化环境
    ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

  • 配置环境信息

    //根据系统类别选择创建的环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //将命令行参数配置到环境里
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //附加配置configurationProperties
    ConfigurationPropertySources.attach(environment);
    //真正的加载和解析配置添加到环境对象,具体事件机制实现
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
    environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
    					deduceEnvironmentClass());
    		}
    ConfigurationPropertySources.attach(environment);

  • 创建上下文环境

      private ConfigurableEnvironment getOrCreateEnvironment() {
      		if (this.environment != null) {
      			return this.environment;
      		}
      		switch (this.webApplicationType) {
      		case SERVLET:
      			return new StandardServletEnvironment();
      		case REACTIVE:
      			return new StandardReactiveWebEnvironment();
      		default:
      			return new StandardEnvironment();
      		}
      	}

事件加载

  • 启动时注册了监听器

      org.springframework.boot.SpringApplicationRunListener=\
      org.springframework.boot.context.event.EventPublishingRunListener

  • 监听器触发

      //监听者发布环境准备事件listeners.environmentPrepared(environment);
      //类EventPublishingRunListener中发布
      public void environmentPrepared(ConfigurableEnvironment environment) {
      this.initialMulticaster
      				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
      	}

  • 之前配置启动的监听器

      # Application Listeners
      org.springframework.context.ApplicationListener=\
      org.springframework.boot.context.config.ConfigFileApplicationListener
      ...

  • 具体触发器

      public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {

          //触发应用事件
          @Override
      	public void onApplicationEvent(ApplicationEvent event) {
      		if (event instanceof ApplicationEnvironmentPreparedEvent) {
      			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
      		}
      		if (event instanceof ApplicationPreparedEvent) {
      			onApplicationPreparedEvent(event);
      		}
      	}

          //环境配置的处理
      private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
      		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
              //自己也是环境处理器
      		postProcessors.add(this);
      		AnnotationAwareOrderComparator.sort(postProcessors);
      		for (EnvironmentPostProcessor postProcessor : postProcessors) {
      			postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
      		}
      	}

      }

  • 环境处理器
      org.springframework.boot.env.EnvironmentPostProcessor=\
      org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
      org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
      //systemEnvironment处理器
      org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
      org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

  • ConfigFileApplicationListener的环境处理器

      protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
              //添加随机值配置功能,${random.long}
      		RandomValuePropertySource.addToEnvironment(environment);
      		new Loader(environment, resourceLoader).load();
      }

      void load() {
                    //具体加载配置文件
      			FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
      					(defaultProperties) -> {
      						this.profiles = new LinkedList<>();
      						this.processedProfiles = new LinkedList<>();
      						this.activatedProfiles = false;
      						this.loaded = new LinkedHashMap<>();
                                //查找配置的profiles
      						initializeProfiles();
                                //支持配置的多个profiles
      						while (!this.profiles.isEmpty()) {
      							Profile profile = this.profiles.poll();
      							if (isDefaultProfile(profile)) {
      								addProfileToEnvironment(profile.getName());
      							}
                                    //具体查询具体配置的文件

      							load(profile, this::getPositiveProfileFilter,
      									addToLoaded(MutablePropertySources::addLast, false));
      							this.processedProfiles.add(profile);
      						}

      						load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
                                 //创建具体的MutablePropertySources,并放入                                                    environment.getPropertySources中
      						addLoadedPropertySources();
                              //激活spring.profiles.include,spring.profiles.active
      						applyActiveProfiles(defaultProperties);
      					});
      		}

  • load过程

      private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,DocumentConsumer consumer) {

      			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);
      					}
      				}
      			}
      		}

属性资源加载器

  • springFactorys中配置

      org.springframework.boot.env.PropertySourceLoader=\
      org.springframework.boot.env.PropertiesPropertySourceLoader,\
      org.springframework.boot.env.YamlPropertySourceLoader

  • 介绍一种Properties的资源加载器

      public class PropertiesPropertySourceLoader implements PropertySourceLoader {
      	private static final String XML_FILE_EXTENSION = ".xml";
          //支持的文件类型
      	@Override
      	public String[] getFileExtensions() {
      		return new String[] { "properties", "xml" };
      	}
         //如果是该资源,创建propertyResources列表
      	@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, Collections.unmodifiableMap(properties), true));
      	}
         //将上述符合条件的Resources返回key-value值
      	@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();
      	}

      }

加载顺序

  • servlet环境首先加载标准参数

      protected void customizePropertySources(MutablePropertySources propertySources) {
      		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
      		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
      		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
      			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
      		}
      		super.customizePropertySources(propertySources);
      	}
      //1:servletConfigInitParams
      //2:servletContextInitParams
      //3:jndiProperties

  • 调用父类加载

        protected void customizePropertySources(MutablePropertySources propertySources) {
              propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
              propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
          }
      //4:systemProperties
      //5:systemEnvironment

  • 加载ConfigFile中的Random

      protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
      		RandomValuePropertySource.addToEnvironment(environment);
      		new Loader(environment, resourceLoader).load();
      	}
      //6:RandomValueProperty

  • 加载命令行中

      configureEnvironment(environment, applicationArguments.getSourceArgs());
      //7:加入命令行参数

  • 加载配置文件

      //8:加载配置了profile中的配置
      //9:加载默认的配置
      while (!this.profiles.isEmpty()) {
      Profile profile = this.profiles.poll();
      	if (isDefaultProfile(profile)) {
      		addProfileToEnvironment(profile.getName());
      	}
      	load(profile, this::getPositiveProfileFilter,addToLoaded(MutablePropertySources::addLast, false));
      		this.processedProfiles.add(profile);
      }
      load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
      addLoadedPropertySources();
      applyActiveProfiles(defaultProperties);

使用

  • 具体注入使用

       @Value("${java.version}")
       private String javaVersion;

  • 使用环境注入

          @Autowired
          Environment environment;

          @GetMapping("/javaVersion")
          public String javaVersion(){
              return environment.getProperty("java.version");
          }



Similar Posts

Comments