SpringBoot-自动配置原理详解

本文详细解析了SpringBoot的自动装配机制,从自动装配的使用到其实现,深入探讨了@SpringBootApplication和@EnableAutoConfiguration注解的作用。通过分析AutoConfigurationImportSelector类,揭示了自动装配类的加载过程。此外,还介绍了如何自定义starter,并提供了相关资源链接供进一步学习。

一、什么是自动装配

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

记住这个spring.factories文件,我们在下面自定义starter启动器是会需要它。

1.1 自动装配的使用

没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

引入starter之后,我们可以通过少量的注解和一些简单的配置就能使用第三方组件提供的功能了。

二、自动装配的实现

自动装配的实现,离不开@SpringBootApplication这个核心注解。

2.1 @SpringBootApplication注解

@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 {

其中,有三个注解是需要我们注意的:

  1. @Configuration

允许在上下文中注册额外的 bean 或导入其他配置类

  1. @EnableAutoConfiguration

启用 SpringBoot 的自动配置机制

  1. @ComponentScan

扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilterh和AutoConfigurationExcludeFilter。

img

2.2 @EnableAutoConfiguration

字面意思来看,该注解是启动自动配置,事实上,@EnableAutoConfiguration也确实是实现自动装配的重要注解。

下面来看下enableAutoConfiguration注解的内容:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

其中AutoConfigurationImportSelector类是加载自动装配类;

AutoConfigurationImportSelector类的结构体系如下:

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

其中,实现的ImportSelector接口中,有一个selectorImports方法也被实现了,该方法主要用于获取所有符合条件的类的全限定类名,然后将这些类加载到Ioc容器中,该方法的具体实现如下:

@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

然后,再来看下其中的getAutoConfigurationEntry()方法,这个方法主要用于加载自动装配类,方法的实现如下:

/**
	 * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
	 * of the importing {@link Configuration @Configuration} class.
	 * @param annotationMetadata the annotation metadata of the configuration class
	 * @return the auto-configurations that should be imported
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
        //step1
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //step2
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//step3
        configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
        //step4
	}

下面来分析下getAutoConfigurationEntry()方法的源码:

  1. 判断自动装配开关是否打开。默认spring.boot.enableautoconfiguration=true,可在 application.properties 或 application.yml 中设置。
if (!isEnabled(annotationMetadata)) {
	return EMPTY_ENTRY;
}

img

  1. 用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。
AnnotationAttributes attributes = getAttributes(annotationMetadata);

img

  1. 获取需要自动装配的所有类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

img

所以,如果,我们自己要创建一个 Spring Boot Starter,这一步是必不可少的:

img

  1. 筛选不需要加载的配置
       configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);

三、自己实现starter

可以参考我的另外一篇博客:

完整版手动实现starter启动器

四、参考

https://www.cnblogs.com/javaguide/p/springboot-auto-config.html

Spring Boot是一个简化Spring应用开发的框架,它通过自动配置的方式来减少开发者的工作量,提高开发效率。SpringBoot自动配置原理是什么呢? 首先,SpringBoot自动配置是基于SpringBoot的starter依赖功能实现的。starter依赖本质上是一个Maven项目,里面包含了一些依赖和必要的资源,只需将这个项目引入到应用中,就能自动加载依赖并进行一些默认配置。Spring Boot框架中一些核心的starter依赖包括spring-boot-starter-web、spring-boot-starter-data-jpa、spring-boot-starter-data-redis等等,开发者可以根据自己的需要引入合适的starter依赖。 其次,SpringBoot自动配置是基于条件注解实现的。条件注解是Spring框架提供的一种特殊注解,它能够根据指定的条件来判断是否需要加载某个组件或配置。Spring Boot中,提供了很多条件注解,如@ConditionalOnClass、@ConditionalOnProperty等等,它们可以根据类是否存在、属性是否配置等条件来决定是否加载某个组件或配置。 最后,SpringBoot自动配置还包含了一些默认的配置,这些默认配置可以通过自定义配置来覆盖或扩展。例如,在使用spring-boot-starter-web时,SpringBoot会默认配置Tomcat容器来运行Web应用,如果开发者需要使用其他容器如Jetty或Undertow,可以写一个配置类来覆盖默认配置。 综上所述,SpringBoot自动配置是基于starter依赖、条件注解和默认配置实现的。它大大减少了开发者的工作量,提高了开发效率,同时也保证了应用的可靠性和稳定性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值