Java architecture train - @ SpringApplication automatic assembly principle

Currently the service is already micro-enterprise standard, as many small partners just to stay in the know these, does not the why of the situation; We are here to summarize the principle of automatic assembly SpringBoot, some content behind the teacher is based SpringBoot this source automatic assembly principle to write code directly, if you understand the principle of automatic assembly of SpringBoot for later learning will be more hundreds of times.

SpringBoot start the process to resolve the principle of automatic assembly principle @SpringApplication

First SpringBoot for a project, the most obvious sign is that @SpringBootApplicationit is a SpringBoot mark this project, so SpringBoot automatic assembly principle today is from it to begin with.

First, we look back at this comment @SpringBootApplication what mystery it, we press Ctrl + left mouse button, gently tap, this time to witness the miracle of the moment ...

We see the following elegant code

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration  
@EnableAutoConfiguration  
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM,
				classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {   
    // 此处省略一万字
    ...
}

This one has two relatively easily lead to our attention, one @SpringBootConfigurationnotes, is another @EnableAutoConfigurationcomment; reason why the two compare notes to attract our attention, not because they grew up nice, but because of other comments too ugly (mainly because of the other comments we are all familiar with, even without knowing they are doing, certainly more automated assembly are not related). Then we stretched out evil little hands, turned the familiar operation, press the Ctrl + left mouse button, staring Se Mimi small eyes, dilated pupils, a hundred times waiting for a miracle ... ... rub rub rub ... ...

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

Nothing ...
then I want you to what is the use, so the top world-class open source project, how to make a useless guy exist? So spent billions of brain cells troops after a complicated operation, we do not fly come to a conclusion that it may use to mark this is a configuration SpringBoot project. Because SpringBootConfiguration translates SpringBoot configuration, so the heart is full steam ahead in the tens of thousands of alpacas, desert flying.

After leisurely, adhering to the "Failure is the mother of success" of the faith, a skilled hand to fill the gap by pressing the Ctrl + Table button to return to the original place. Staring at @EnableAutoConfiguration, look around, in the address bar enter the Google translation, the results show automatic assembly. I'm looking for is that you really no trace of her thousands of Baidu, that person is in the dim lights. Skilled pressed Ctrl + Left, can not wait to enter; silently recite from the "Land of Peach Blossoms" classic verse:

Forest to make water, they have a mountain, the mountain has a small mouth, as though if the light. Then round the ship, from the mouth. Beginning of a very narrow, only Walter. Re-line Shu Shibu, suddenly

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // 此处省略100字
    ...
}

At this moment people feel good, then have had previous experience in the face of the new world, we calm a lot. At this point the brain high-speed operation, no longer entangled, destroy Huanglong, entered the AutoConfigurationImportSelector.class class because Google translator to tell us, this is automatically configured to import selector. So we found a new world.

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {


    @Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		// 获取自动配置的实体
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
				autoConfigurationMetadata, annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

    // 具体用来加载自动配置类的方法
	protected AutoConfigurationEntry getAutoConfigurationEntry(
			AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 获取候选的配置类,即使后宫佳丽三千,也是要筛选的
		List<String> configurations = getCandidateConfigurations(annotationMetadata,
				attributes);
		// 根据情况,自动配置需要的配置类和不需要的配置了
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		// 返回最终需要的配置
		return new AutoConfigurationEntry(configurations, exclusions);
	}
}

And this entity AutoConfigurationEntry automatic configuration there are two attributes, configurations and exclusions.

protected static class AutoConfigurationEntry {
    	// 用来存储需要的配置项
		private final List<String> configurations; 
   	 	// 用来存储排除的配置项
		private final Set<String> exclusions;      
		
		private AutoConfigurationEntry() {
       	 	this.configurations = Collections.emptyList();
   			this.exclusions = Collections.emptySet();
        }
}

In the back you can see getAutoConfigurationEntry () method returns an object return new AutoConfigurationEntry (configurations, exclusions) here is the configuration we need to have got.

That is how he got the candidate configuration class it? We then get to see this kind of candidate configuration method

List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);

We see the method proceeds to the following method of obtaining a candidate specific configuration content class

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		List<String> configurations = 			 	        				SpringFactoriesLoader.loadFactoryNames(
				getSpringFactoriesLoaderFactoryClass(), 	   				 getBeanClassLoader());
		Assert.notEmpty(configurations,
				"No auto configuration classes found in  					META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure 					that file is correct.");
		return configurations;
	}

Here we follow the break to go first into the getSpringFactoriesLoaderFactoryClass () method

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
	// 返回的是	EnableAutoConfiguration字节码对象
    return EnableAutoConfiguration.class;
}

Then we enter getBeanClassLoader () method, this is a class loader

protected ClassLoader getBeanClassLoader() {
		return this.beanClassLoader;
}

Finally, we enter loadFactoryNames () method, which is to find a candidate just based on the configuration of the class bytecode files and class loader. Pass over bytecode

public static List<String> loadFactoryNames(Class<?> 				factoryClass, @Nullable ClassLoader classLoader) {
	// 获取的EnableAutoConfiguration.class的权限定名 	   //org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String factoryClassName = factoryClass.getName();
		return                          					 		  		           loadSpringFactories(classLoader).getOrDefault(factoryClassNa		me, Collections.emptyList());
	}

As shown below:
Here Insert Picture Description

Finally, to obtain all the configuration class by loadSpringFactories ()

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
	// 缓存加载的配置类,	
    MultiValueMap<String, String> result = 			 	 	 	 						cache.get(classLoader);
	if (result != null) {
		return result;
	}
	try {
		Enumeration<URL> urls = (classLoader != null ?		//	去资源目录下找	 				 	 	 	 	classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
//	去系统资源目录下找						ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
	result = new LinkedMultiValueMap<>();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = 	          					 	PropertiesLoaderUtils.loadProperties(resource);
		for (Map.Entry<?, ?> entry properties.entrySet()) {
			String factoryClassName = ((String) 									entry.getKey()).trim();
			for (String factoryName : 								StringUtils.commaDelimitedListToStringArray((String) 				entry.getValue())) {
				result.add(factoryClassName, 											factoryName.trim());
					}
				}
			}
            // 加载完成放到缓存中
			cache.put(classLoader, result);
            // 返回加载到的配置类
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to 						load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

Here we look at how FACTORIES_RESOURCE_LOCATION loaded from the resource directory path to the configuration file is loaded

public final class SpringFactoriesLoader {
	public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

That is, when the project will start to load all the files in all spring.factories META-INF, we found about this file, I built a simple SpringBoot project, it will go to the three jar inside to find the relevant the configuration class.
Here Insert Picture Description

However, the last category is the automatic assembly of spring-boot-autoconfigure-2.1.5.RELEASE.jar
Here Insert Picture Description

According EnableAutoConfiguration.class loading bytecode class only this configuration automatic configuration class 118
Here Insert Picture Description
Here Insert Picture Description

summary

In fact, the principle of automatic assembly SpringBoot, in fact, when the project started to load spring.factories file in the META-INF, did not seem so tall on. Of course, in the process of starting there will be loads of other configuration items, here what we say so automatic assembly of the loading process. I hope we can inspire.

Question: understand the principle of automatic assembly SpringBoot, if we need to get the project started when he loaded our custom configuration class, how to write it?

Published 364 original articles · won praise 324 · Views 150,000 +

Guess you like

Origin blog.csdn.net/No_Game_No_Life_/article/details/103934500