Spring Boot自动配置与run执行流程

1、自动配置

自动配置:根据添加的jar包依赖,会自动将一些配置类的bean注册到IoC容器中,可以在需要的地方使用@Autowired或者@Resuorce等注解来使用它。
Spring Boot应用的启动入口是@SpringBootApplication注解标注类中的main()方法。

1.1、@SpringBootApplication

SpringBootAppliaction注解源码中核心代码如下:


@Target(ElementType.TYPE) //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举中
@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时
@Documented //表示注解可以记录在javadoc中
@Inherited //表示可以被子类继承该注解

@SpringBootConfiguration  // 标明该类为配置类
@EnableAutoConfiguration  // 启动自动配置功能
@ComponentScan(excludeFilters = {
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) //注解扫描
public @interface SpringBootApplication {
   


	// 根据class来排除特定的类,使其不能加入spring容器,传入参数value类型是class类型。
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {
   };

	// 根据classname 来排除特定的类,使其不能加入spring容器,传入参数value类型是class的全类名字符串数组
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {
   };

	// 指定扫描包,参数是包名的字符串数组。
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {
   };

	// 扫描特定的包,参数类似是Class类型数组。
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {
   };

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

从源码中可以看出,@SpringBootApplication注解是一个组合注解,前面四个是注解的元数据信息,我们主要看@SpringBootConfiguration、@EnableAutoConfiguration、@ComponetScan三个核心注解

1.2、@SpringBootConfiguration

@SpringBootConfiguration:SpringBoot的配置类,标注在某个类上,表示这是一个SpringBoot的配置类
@SpringBootConfiguration注解源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented

@Configuration
public @interface SpringBootConfiguration {
   

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

从上述源码可以看出,@SpringBootConfiguration注解内部有一个核心注解@Configuration,该注解是Spring框架提供的,表示当前类为一个配置类,并可以被组件扫描器扫描。由此可见,@SpringBootConfiguration注解的作用与@Configuration注解相同,都是标识一个可以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是配Spring Boot进行的重新封装命名而已

1.3、@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

@AutoConfigurationPackage // 自动配置包
@Import(AutoConfigurationImportSelector.class) // Spring的底层注解@Import,给容器中导入一个组件;
public @interface EnableAutoConfiguration {
   

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	// 返回不会被导入到Spring容器中的类
	Class<?>[] exclude() default {
   };

	// 返回不会被导入到Spring容器中的类名
	String[] excludeName() default {
   };

}

Spring中有很多以Enable开头的注解,其作用就是借助@Import来收集并注册特定场景相关的Bean,并加载到IoC容器中。
@EnableAutoConfiguration就是借助@Import来收集所有符合自动配置条件的bean定义,并加载到IoC容器。

1.3.1、@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

// Spring的底层注解@Import,给容器中导入一个组件;
// 导入的组件是AutoConfigurationPackages.Registrar.class
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
   

}

@AutoConfigurationPackage:自动配置包,它也是个组合注解,其中最重要的注解就是@Import(AutoConfigurationPackages.Registrar.class),它是Spring框架底层的注解,它的作用就是给容器中导入某个组件类,本处就是将Registrar这个组件类导入到容器中,其中Registrar类中的registerBeanDefinitions方法如下:

public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
   
			// 将注解标注的元信息传入,获取到相应的包名
			register(registry, new PackageImport(metadata).getPackageName());
		}

new PackageImport(metadata).getPackageName()返回了当前启动类所在包名,再看register方法

public static void register(BeanDefinitionRegistry registry, String... packageNames) {
   
		// 这里参数 packageNames 缺省情况下就是一个字符串,是使用了注解
		// @SpringBootApplication 的 Spring Boot 应用程序入口类所在的包

		if (registry.containsBeanDefinition(BEAN)) {
   
			// 如果该bean已经注册,则将要注册包名称添加进去
			BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
			ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
			constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
		}
		else {
   
			//如果该bean尚未注册,则注册该bean,参数中提供的包名称会被设置到bean定义中去
			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(BasePackages.class);
			beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			registry.registerBeanDefinition(BEAN, beanDefinition);
		}
	}

AutoConfigurationPackages.Registrar类就做了一个事,注册一个Bean,这个Bean就是com.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages,它有一个参数,这个参数是使用了@AutoconfigurationPackage这个注解的类所在的包路径,保存自动配置类以供之后的使用,比如给JPA entity扫描器用来扫描开发人员通过注解@Entity定义的entity类。

1.3.2、@Import(AutoConfigurationImportSelector.class)

@Import(AutoConfigurationImportSelector.class)AutoConfigurationImportSelector这个类导入到Spring容器中,AutoConfigurationImportSelector可以帮助SpringBoot应用将所有符条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器中。
在这里插入图片描述
可以看到AutoConfigurationImportSelector重点是实现了DeferredImportSelector接口又继承了ImportSelector接口。它还是实现了很多其他的Aware接口,分别表示在某个时机会被回调。

1.3.2.1、自动配置实现逻辑的入口方法

跟自动配置逻辑相关的入口方法在DeferredImportSelectorGrouping类的getImports方法处,因此就从DeferredImportSelectorGrouping类的getImports方法开始分析SpringBoot的自动配置源码。
如下为DeferredImportSelectorGrouping类的getImports方法源码:

public Iterable<Group.Entry> getImports() {
   
	// 遍历DeferrdImportSelectorHolder对象集合deferredImports,deferredImports集合装了各种ImportSelectory,在此处装的是AutoConfigurationImportSelector
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
   
		//[1] 利用AutoConfigurationGroup的process方法来处理自动配置的相关逻辑,决定导入哪些配置类
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
			deferredImport.getImportSelector());
	}
	//[2] 经过上面的处理,然后再进行选择导入哪些配置类
	return this.group.selectImports();
}

如上代码,注释[1]处,自动配置的相关的绝大部分逻辑在此处,即调用AutoConfigurationGroup对象的process方法,传入的AutoConfigurationImportSelector对象来选择一些符合条件的自动配置类,过滤掉一些不符合条件的自动配置类。

注:
AutoConfigurationGroup:是AutoConfigurationImportSelector的内部类,主要用来处理自动配置相关逻辑,拥有process和selectImports方法,然后拥有entries和autoConfigurationEntries集合属性,这两个集合分别存储被处理后的符合条件的自动配置类。
AutoConfigurationImportSelector:承担自动配置的绝大部分逻辑,负责选择一些符合条件的自动配置类。
metadata:标注在SpringBoot启动类上的@SpringBootApplication注解元数据。
注释[2] 处的this.group.selectImports的方法主要是针对前面process方法处理后的自动配置类再进一步筛选导入

再进入到AutoConfigurationImportSelector$AutoConfigurationGroup的pross方法:
于第一行断点调试,可以看到与自动配置逻辑相关的入口方法在process方法中
在这里插入图片描述

1.3.2.2、自动配置的主要逻辑
		@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()));

			// 【1】,调用getAutoConfigurationEntry方法得到自动配置类放入autoConfigurationEntry对象中
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);

			// 【2】,又将封装了自动配置类的autoConfigurationEntry对象装进autoConfigurationEntries集合
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			// 【3】,遍历刚获取的自动配置类
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
   
				// 这里符合条件的自动配置类作为key,annotationMetadata作为值放进entries集合
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

在【1】处调用了getAutoConfigurationEntry方法,这个方法主要是用来获取自动配置相关类,承担了自动配置的主要逻辑。代码如下:

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
   
		// 获取是否有配置spring.boot.enableautoconfiguration属性
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值