springboot2.1.7 startup analysis (two) SpringApplication run

table of Contents

 

SpringApplicationRunListeners listeners = getRunListeners(args); 

 listeners.starting()

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments)


 

SpringApplicationRunListeners listeners = getRunListeners(args);

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}
	SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<>(listeners);
	}

 SpringApplicationRunListeners saves a collection of SpringApplicationRunListener types, and SpringApplicationRunListener is also obtained from the META-INF/spring.factories file and instantiated by reflection. The constructor with parameters is called during reflection, and currently it has a value of EventPublishingRunListener, as shown below. It can be seen that the multicast in EventPublishingRunListener saves the ApplicationListener instance when SpringApplication is instantiated.

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}

 listeners.starting()

	public void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}
//EventPublishingRunListener
	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

The multicaster broadcasts an ApplicationStartingEvent event, and all listeners that support the ApplicationStartingEven event execute the onApplicationEvent event processing method

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)

Encapsulates the startup parameters, such as the applicaton file (dev, prod) specified at startup

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments)

	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        //广播environmentPrepared事件
		listeners.environmentPrepared(environment);
        //将环境绑定到SpringApplication
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
        //环境转换器(当前不需要转换,所以还是标准的servlet环境)
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
        //将ConfigurationPropertySource支持附加到指定的Environment 。 使环境管理的每个PropertySource适应ConfigurationPropertySource并允许经典的PropertySourcesPropertyResolver调用使用configuration property names进行解析
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
  • environment: StandardServletEnvironment. PropertySources will be customized when StandardServletEnvironment is instantiated.
public AbstractEnvironment() {
   customizePropertySources(this.propertySources);
}

StandardServletEnvironment custom attributes will take precedence over the system attributes and environment variables provided by the StandardEnvironment superclass. And the attribute source related to Servlet is added as stubs at this stage, and will be fully initialized when the actual ServletContext object is available. Therefore, the sources corresponding to servletConfigInitParams and servletContextInitParams are empty objects and serve as placeholders. The parent class StandardEnvironment custom property source systemProperties (System.getProperties()) and systemEnvironment (System.getenv()) correspond to sources value.

  •  configureEnvironment: configure the environment. Method annotation translation: The template method is delegated to configurePropertySources(ConfigurableEnvironment, String[]) and configureProfiles(ConfigurableEnvironment, String[]) in this order. Override this method to fully control the environment customization, or override one of the above methods to have fine-grained control over property sources or configuration files, respectively. Because SpringApplication can be rewritten, some methods can be rewritten.
    	protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    		if (this.addConversionService) {
    			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
    			environment.setConversionService((ConfigurableConversionService) conversionService);
    		}
    		configurePropertySources(environment, args);
    		configureProfiles(environment, args);
    	}
    ConversionService:用于类型转换的服务接口。 这是转换系统的入口。 调用convert(Object, Class)使用此系统执行线程安全的类型转换。并将此实例设置到environment属性propertyResolver中。
    configurePropertySources:配置属性源。主要是通过启动参数添加或替换属性源,在启动时指定defaultProperties添加defaultProperties属性源(例如SpringApplicationBuilder的properties(String... defaultProperties)方法)
    configureProfiles:配置该应用程序环境中哪些配置文件处于活动状态。在配置文件处理期间,可以通过{@code spring.profiles.active}属性激活其他配置文件。主要是通过查找StandardServletEnvironment中propertySources中是否有对应的key。
  • listeners.environmentPrepared(environment): broadcast the environmentPrepared event. The debugging source code found here mainly focuses on the onApplicationEvent of ConfigFileApplicationListener. onApplicationEvent will call the onApplicationEnvironmentPreparedEvent method, which will first find all instances of EnvironmentPostProcessor (the post processor of the environment) through SpringFactoriesLoader.loadFactories (META-INF/spring.factories), and execute the postProcessEnvironment method of each instance in turn. Here is still only concerned about the EnvironmentPostProcessor ConfigFileApplicationListener. The key code is as follows: Add the configuration file attribute source to the specified environment.
	protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		new Loader(environment, resourceLoader).load();
	}

 The PropertySourceLoader that parses properties and yaml files is found through the Loader constructor. These PropertySourceLoaders are also instantiated through SpringFactoriesLoader.loadFactories.

load method.   

1. initializeProfiles(): Initialize a null and default profile. null is to read application.yml/applicaton.properties.

2. Circulate processing profiles. First process the profile whose value is null, read the spring.profiles.active value (such as dev), and then add the dev profile and remove the default profile. Then the dev profile is processed in a loop. Because the profile is not empty and not the default, the name of the profile will be set to the profile of the environment (code 1 below)

3. addLoadedPropertySources: StandardServletEnvironment adds the installed PropertySources (as shown in Figures 5 and 6 below)

                                                                                                                       A screenshot of the part of the PropertySource corresponding to application.yml: 

		public void load() {
			this.profiles = new LinkedList<>();
			this.processedProfiles = new LinkedList<>();
			this.activatedProfiles = false;
			this.loaded = new LinkedHashMap<>();
			initializeProfiles();
			while (!this.profiles.isEmpty()) {
				Profile profile = this.profiles.poll();
                //1
				if (profile != null && !profile.isDefaultProfile()) {
					addProfileToEnvironment(profile.getName());
				}
				load(profile, this::getPositiveProfileFilter, addToLoaded(MutablePropertySources::addLast, false));
				this.processedProfiles.add(profile);
			}
			resetEnvironmentProfiles(this.processedProfiles);
			load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
			addLoadedPropertySources();
		}

	private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			getSearchLocations().forEach((location) -> {
				boolean isFolder = location.endsWith("/");
				Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
		}

GetSearchLocations method analysis: DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/", that is, the path where springboot finds the configuration file. You can see that the asResolvedSet method first sets the string It is parsed as a list collection and then reversed, so the order in which springboot looks for configuration files is:

		
		private Set<String> getSearchLocations() {
			if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
				return getSearchLocations(CONFIG_LOCATION_PROPERTY);
			}
			Set<String> locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);
			locations.addAll(
					asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS));
			return locations;
		}

private Set<String> asResolvedSet(String value, String fallback) {
			List<String> list = Arrays.asList(StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(
					(value != null) ? this.environment.resolvePlaceholders(value) : fallback)));
			Collections.reverse(list);
			return new LinkedHashSet<>(list);
		}

 

Guess you like

Origin blog.csdn.net/sinat_33472737/article/details/112762032