springBoot学习笔记源码分析之@springbootApplication

Posted 拐柒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springBoot学习笔记源码分析之@springbootApplication相关的知识,希望对你有一定的参考价值。

源码剖析之@springbootApplication

springboot-starter

我们在创建springboot项目中pom.xml中不需要进行依赖的版本配置,是因为在springboot-starter-parent的父级spring-boot-dependencies中已经替我们配置好了一些第三方框架的依赖。如果我们使用的第三方框架没有和springboot进行集成,这个时候我们就需要进行版本配置。

springboot自动配置之@springbootApplication

根据我们添加的jar依赖,springboot会自动的将一些配置类和的bean注册进ioc容器中,我们可以在需要的地方使用@autowried或者@Resource注解来使用他。

@SpringBootConfiguration

@SpringBootApplication是一个组合注解。其中@SpringBootConfiguration表明了SpringBootApplication是一个配置类,被SpringBootApplication标注的类,是主配置类。

@EnableAutoConfiguration

@EnableAutoConfiguration注解也是一个组合注解,由@AutoConfigurationPackage,@Import(AutoConfigurationImportSelector.class)构成。
Spring 中有很多以 Enable 开头的注解,其作用就是借助 @Import 来收集并注册特定场景相关的Bean ,并加载到 IOC 容器。
@EnableAutoConfiguration就是借助@Import来收集所有符合自动配置条件的bean定义,并加载到
IoC容器。

@AutoConfigurationPackage

package org.springframework.boot.autoconfigure;
 @Import(AutoConfigurationPackages.Registrar.class) // 导入Registrar中注册的组件 
 public @interface AutoConfigurationPackage { }

@AutoConfigurationPackage :自动配置包,它也是一个组合注解,其中最重要的注解是@Import(AutoConfigurationPackages.Registrar.class) ,它是 Spring 框架的底层注解,它的作用就是给容器中导入某个组件类,例如
@Import(AutoConfigurationPackages.Registrar.class) ,它就是将 Registrar 这个组件类导入到容器中。AutoConfigurationPackages.Registrar这个类就干一个事,注册一个 Bean ,这个 Bean 就是org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages ,它有一个参数,这个参数是使用了 @AutoConfigurationPackage 这个注解的类所在的包路径,保存自动配置类以供之后的使用。

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector中的内部类AutoConfigurationGroup主要用来处理自动配置相关的逻辑,拥有peocess和selectImports方法。

process方法

@Override
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

getAutoConfigurationEntry方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//1、获取所有META-INF 下spring.factory文件中 key为 EnableAutoConfiguration注解全路径的value值,即为需要装配的所有配置文件全限定类名
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//2、去重
		configurations = removeDuplicates(configurations);
		//3、排除一些全限定类名,即添加在@springbootappliciton(exclude = "xxx")中的class
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		//4、检查排除的类名是不是一个配置类
		checkExcludedClasses(configurations, exclusions);
		//5、进行排除
		configurations.removeAll(exclusions);
		//6、因为从spring.factories文件获取的自动配置类太多,如果有些不必要的自动配置类都加载 进内存,会造成内存浪费,因此这里需要进行过滤
		// 注意这里会调用AutoConfigurationImportFilter的match方法来判断是否符合 @ConditionalOnBean,@ConditionalOnClass或@ConditionalOnWebApplication
		//即判断是否符合以@Conditional注解开头的注解条件,例如@ConditionalOnClass(RibbitMQ.Class),即判断classpath下是不是引入了mq相关的jar
		configurations = filter(configurations, autoConfigurationMetadata);
		// 7 、获取了符合条件的自动配置类后,此时触发AutoConfigurationImportEvent事件,
		// 目的是告诉ConditionEvaluationReport条件评估报告器对象来记录符合条件的自动配置类
		// 该事件什么时候会被触发?--> 在刷新容器时调用invokeBeanFactoryPostProcessors后置处 理器时触发
		fireAutoConfigurationImportEvents(configurations, exclusions);
		// 8、将符合条件和要排除的自动配置类封装进AutoConfigurationEntry对象,并返回
		return new AutoConfigurationEntry(configurations, exclusions);
	}

@ComponentScan

如果没有指定basePackages属性,那么springboot启动时候便会扫描被@ComponentScan标注类的所在包。

以上是关于springBoot学习笔记源码分析之@springbootApplication的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot源码分析----SpringBoot自动配置

Spring Boot加载配置文件的完整步骤

SpringBoot学习笔记——自动配置原理

SpringBoot配置外部Tomcat项目启动流程源码分析(上)

SpringBoot配置外部Tomcat项目启动流程源码分析(上)

SpringBoot源码分析之SpringApplication构造方法核心源码分析