SpringBoot源码分析一(自动装配原理)

SpringBoot源码分析一(自动装配原理),第1张

SpringBoot源码分析一(自动装配原理) SpringBoot源码分析一(自动装配原理)

文章目录

SpringBoot源码分析一(自动装配原理)

什么是Spring Boot特点maven依赖入口@SpringBootApplication@SpringBootConfiguration@EnableAutoConfiguration

@AutoConfigurationPackage@import(AutoConfigurationimportSelector.class) 核心方法:总结:

官网: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依赖



    4.0.0

    org.example
    springboot-test
    1.0-SNAPSHOT


    
        
            org.springframework.boot
            spring-boot-starter-web
            2.6.2
        

    

入口
@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容器中。如下

	
	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 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 configurations = getCandidateConfigurations(annotationmetadata, attributes);
		...
	}

getCandidateConfigurations() 方法会给容器中注入众多的自动配置类(xxxAutoConfiguration),就是导入这个场景所需要的所有组件,并配置好这些组件。

	protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
		List 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 loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
		......
		return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
	}

	private static Map> loadSpringFactories(ClassLoader classLoader) {
		Map> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		result = new HashMap<>();
		try {
           	// 获取加载所有默认的自动配置类
			Enumeration 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。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5706993.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)