General framework, after the startup will load the configuration file as soon as possible, SpringBoot is no exception, the following start to analyze the springboot load configuration file process.


The springBoot configuration is loaded from the Listener class. Remember in the last section I said that the listener class is not easy to call, so this section starts with the listener class.

Where listeners are initialized in the run method.

public ConfigurableApplicationContext run(String... args) { ... SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); . }Copy the code

The Listener class is stored in the listeners listeners file when the SpringApplication object is initialized. The listeners are stored in the listeners file.

private SpringApplicationRunListeners getRunListeners(String[] args) { Class<? >[] types = new Class<? >[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
				SpringApplicationRunListener.class, types, this, args));
	}
Copy the code

GetRunListeners method, first of all get the SpringApplicationRunListener object, and using SpringApplication, and args as a constructor parameter. And then use the SpringApplicationRunListener collection of objects as parameters, SpringApplicationRunListeners object is constructed. Let’s go to see what was SpringApplicationRunListener object.

GetSpringFactoriesInstances this method we should be very ripe, from SpringApplication object when new has been in the call, so we can see the directly to the configuration file, What is acquired SpringApplicationRunListener object.

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
	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);
		}
	}
Copy the code

EventPublishingRunListener object is found in the configuration file, this is the SpringApplicationRunListener getRunListeners method for object, the constructor is very simple, I wouldn’t have analyzed in detail. Originally SpringApplication listener object in the class, now is encapsulated to EventPublishingRunListener object.

Come back to see again, SpringApplicationRunListener class is encapsulated to SpringApplicationRunListeners objects, it performed getRunListeners method of logic.

Now take a look at the calling logic for the function.starting () method.

	public void starting() {
		for(SpringApplicationRunListener listener: this. Listeners) {/ / traverse the listener call starting method. The starting (); } } public voidstarting() {// This encapsulates an event, Probably guess should be going to use the strategy pattern enclosing initialMulticaster. MulticastEvent (new ApplicationStartingEvent (enclosing application, enclosing the args)); } public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableTypetype= (eventType ! = null ? eventType : resolveDefaultEventType(event)); / / getApplicationListeners obtained in line with the strategy of the listenerfor(final ApplicationListener<? > listener : getApplicationListeners(event,type)) {
			Executor executor = getTaskExecutor();
			if(executor ! = null) { executor.execute(() -> invokeListener(listener, event)); }else{ invokeListener(listener, event); } } } protected void invokeListener(ApplicationListener<? > listener, ApplicationEvent event) { ...doInvokeListener(listener, event); . } private voiddoInvokeListener(ApplicationListener listener, ApplicationEvent event) { ... listener.onApplicationEvent(event); . }Copy the code

Finally, you see the listener execute in the doInvokeListener method. The policy pattern used by all listener execution can be configured in the listener onApplicationEvent method if you want to comply with certain events. Here, too, we can feel the normative nature of the Spring framework’s design, using policy patterns that can be easily extended based on events.


Now that we’ve looked at the startup logic of the Listener class, let’s start analyzing the loading of configuration files.

public ConfigurableApplicationContext run(String... args) { ... ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); . } private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ... listeners.environmentPrepared(environment); . }Copy the code

In the Run method, find the prepareEnvironment method, and when you go in, you’ll see that the listener started the environmentPrepared event, so we’ll go inside the listener and look for listeners that match the environment event.

Name can also look out, he is ConfigFileApplicationListener. Find his onApplicationEvent method and start analyzing.

	public void onApplicationEvent(ApplicationEvent event) {
		if(event instanceof ApplicationEnvironmentPreparedEvent) {/ / entrance onApplicationEnvironmentPreparedEvent here ( (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 : {// There are a few other listeners here, but the most important one is itself. So, We are still postProcessEnvironment approach for the analysis of his own postProcessor. PostProcessEnvironment (event. GetEnvironment (), event.getSpringApplication()); }}Copy the code

The postProcessEnvironment method logic is as follows

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { addPropertySources(environment, application.getResourceLoader()); } protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); New Loader(environment, resourceLoader).load(); Loaders (ConfigurableEnvironment environment, ResourceLoader ResourceLoader) {this.environment = environment; this.placeholdersResolver = new PropertySourcesPlaceholdersResolver( this.environment); this.resourceLoader = (resourceLoader ! = null) ? resourceLoader : new DefaultResourceLoader(); // This method is again seen, without further ado, Open the configuration file. This propertySourceLoaders = SpringFactoriesLoader. LoadFactories (PropertySourceLoader. Class, getClass().getClassLoader()); } / / this is the source of the yml and properties configuration support org. Springframework. Boot. The env. PropertySourceLoader = \ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoaderCopy the code

The Loader class gets support for the YML and Properties profiles in the constructor. Let’s start with the load function.

		public void load() {... // The configuration logic of the profile is not complicated. The key method is to load the load (null, this: : getNegativeProfileFilter, addToLoaded (MutablePropertySources: : addFirst,true)); . } private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {getSearchLocations().foreach ((location) -> {Boolean isFolder = location.endsWith("/"); // Focus on the getSearchNames method Set<String> names = isFolder? getSearchNames() : NO_SEARCH_NAMES; names.forEach( (name) -> load(location, name, profile, filterFactory, consumer)); }); }Copy the code

In getSearchLocations approach, you can see if there is no specified address, the default address is “classpath: /, the classpath: / config/file:. /, file:. / config/”, if want to specify, The spring.config.location parameter is required for startup

In the getSearchNames method, you can see that if no profile name is specified, the profile name is searched by Application. If you want to specify it, you need to add the spring.config.name parameter at startup

So let’s move on to the load method

		private void load(String location, String name, Profile profile,
				DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			...
			Set<String> processed = new HashSet<>();
			for (PropertySourceLoader loader : this.propertySourceLoaders) {
				for (String fileExtension : loader.getFileExtensions()) {
					if (processed.add(fileExtension)) {
						loadForFileExtension(loader, location + name, "."+ fileExtension, profile, filterFactory, consumer); }}}}Copy the code

In the load method of this layer, you see the yML and Properties format support classes propertySourceLoaders that you get when the Loader class is created, and look at the getFileExtensions method of both classes

public class YamlPropertySourceLoader implements PropertySourceLoader {

	@Override
	public String[] getFileExtensions() {
		return new String[] { "yml"."yaml" };
	}

public class PropertiesPropertySourceLoader implements PropertySourceLoader {

	private static final String XML_FILE_EXTENSION = ".xml";

	@Override
	public String[] getFileExtensions() {
		return new String[] { "properties"."xml" };
	}
Copy the code

At this point, we finally figured out why the default configuration file name had to be Application and could be in either YML or Properties format.

The final loading process is really not much to analyze. After all of our operations, we have successfully traced the source of the SpringBoot default configuration load and learned what to do if we want to specify the configuration.


Returns the directory