SpringBoot源码分析一(自动装配原理)
   
     文章目录
    
官网:https://spring.io/projects/spring-boot
目前最新版本为 2.6.2
简介:来自官网第一句话。
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.
Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,您可以“直接运行”这些应用程序。
大多数 Spring Boot 应用程序需要最少的 Spring 配置。
    
    
    什么是Spring Boot
   
- 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动配置)的理念让你的项目快速运行起来。
- 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 Maven 整合了所有的 jar 包一样,Spring Boot 整合了所有框架
    
    
    特点
   
- 创建独立的 Spring 应用程序
- 直接嵌入Tomcat、Jetty或Undertow(无需部署WAR文件)
- 提供自以为是的“入门”依赖项以简化您的构建配置
- 尽可能自动配置 Spring 和 第三方库
- 提供生产就绪功能,例如指标、运行状况检查和外部化配置
- 完全不需要代码生成,也不需要 XML 配置
    
    
    maven依赖
   
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.example</groupId>
    <artifactId>springboot-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.2</version>
        </dependency>
    </dependencies>
</project>
    
    
    入口
   
@SpringBootApplication
@RestController
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
    @GetMapping("")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        return String.format("Hello %s!", name);
    }
}
     
   
    
    
    @SpringBootApplication
   
这个注解标注于某个类上,说明这个类是Spring Boot的主配置类,通过运行这个类的 main 方法来启动 Spring Boot。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
    
    
    @SpringBootConfiguration
   
- Spring Boot的配置类
- 标注在某个类上,表示这是一个Spring Boot的配置类
注解定义如下:
@Configuration
public @interface SpringBootConfiguration {}
    其实就是一个
    
     Configuration配置类
    
    ,意思是 MyApplication 最终会被注册到Spring容器中
   
    
    
    @EnableAutoConfiguration
   
- 开启自动配置功能
- 以前使用Spring需要配置的信息,Spring Boot帮助自动配置;
- 
     
 @EnableAutoConfiguration
 
 通知SpringBoot开启自动配置功能,这样自动配置才能生效。
注解定义如下:
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
    
    
    @AutoConfigurationPackage
   
- 自动配置包注解
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}
    
     @Import(AutoConfigurationPackages.Registrar.class)
    
    :默认将主配置类(
    
     @SpringBootApplication
    
    )所在的包及其子包里面的所有组件扫描到Spring容器中。如下
   
	/**
	 * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
	 * configuration.
	 */
	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            // 默认将会扫描@SpringBootApplication标注的主配置类所在的包及其子包下所有组件
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}
		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImports(metadata));
		}
	}
    
    
    @Import(AutoConfigurationImportSelector.class)
   
EnableAutoConfigurationImportSelector: 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中
@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
        
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
        
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		...
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		...
	}
    
     getCandidateConfigurations()
    
    方法会给容器中注入众多的自动配置类(xxxAutoConfiguration),就是导入这个场景所需要的所有组件,并配置好这些组件。
   
	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;
	}
	
	protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}
    
     loadFactoryNames()
    
    从类路径的META-INF/spring.factories中加载所有默认的自动配置类
   
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		......
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}
	private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
		Map<String, List<String>> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}
		result = new HashMap<>();
		try {
           	// 获取加载所有默认的自动配置类
			Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			
             ......
			// Replace all lists with unmodifiable lists containing unique elements
			result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
					.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
			cache.put(classLoader, result);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
		return result;
	}
    SpringBoot启动的时候从类路径下的
    
     META-INF/spring.factories
    
    中获取EnableAutoConfiguration指定的值,并将这些值作为自动配置类导入到容器中,自动配置类就会生效,最后完成自动配置工作。EnableAutoConfiguration默认在spring-boot-autoconfigure这个包中。
   
在这里插入图片描述
最终有96个自动配置类被加载并注册进Spring容器中。
J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-xxx.jar中。在这些自动配置类中会通过@ConditionalOnClass等条件注解判断是否导入了某些依赖包,从而通过@Bean注册相应的对象进行自动配置。后面我们会有单独文章讲自动配置的内容
@ConditionalOnBean         //	当给定的在bean存在时,则实例化当前Bean
@ConditionalOnMissingBean  //	当给定的在bean不存在时,则实例化当前Bean
@ConditionalOnClass        //	当给定的类名在类路径上存在,则实例化当前Bean
@ConditionalOnMissingClass //	当给定的类名在类路径上不存在,则实例化当前Bean
    
    
    核心方法:
   
selectImports() -> getAutoConfigurationEntry() -> getCandidateConfigurations() -> SpringFactoriesLoader.loadFactoryNames() -> loadSpringFactories()
    
    
    总结:
   
    路径上存在,则实例化当前Bean
    
    @ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean
   
## 核心方法:
selectImports() -> getAutoConfigurationEntry() -> getCandidateConfigurations() -> SpringFactoriesLoader.loadFactoryNames() -> loadSpringFactories()
## 总结:
> SpringBoot启动的时候通过@EnableAutoConfiguration注解找到META-INF/spring.factories文件中的所有自动配置类,并对其加载,这些自动配置类都是以AutoConfiguration结尾来命名的。它实际上就是一个JavaConfig形式的IOC容器配置类,通过以Properties结尾命名的类中取得在全局配置文件中配置的属性,如server.port。
 
