《深入探究 @SpringBootApplication 注解的内部原理》

《深入探究 @SpringBootApplication 注解的内部原理》

@SpringBootApplication注解涵盖了 Spring Boot 的包扫描原理、自动装配原理等众多重要原理。接下来,我们将对该注解展开深入且详尽的研究。而研究上述原理的关键,在于剖析@SpringBootApplication内部的构成结构,如下图:

下面对@SpringBootConfiguration和@EnableAutoConfiguration进行详解。

一、@SpringBootConfiguration注解

内部结构:

@Configuration是Spring的一个注解,其修饰的类会加入Spring容器。这就说明SpringBoot的启动类会加入Spring容器。

进入内部:

该注解会被注入到IOC容器中

二、@EnableAutoConfiguration注解

内部结构:

@AutoConfigurationPackage注解:

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}

其内部@Import进来的类AutoConfigurationPackages.Registrar类:

源码如下:

java 复制代码
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImport(metadata).getPackageName());
		}

		@Override
		public Set<Object> determineImports(AnnotationMetadata metadata) {
			return Collections.singleton(new PackageImport(metadata));
		}

	}

进入registerBeanDefinitions方法中的register方法:

java 复制代码
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
		if (registry.containsBeanDefinition(BEAN)) {
			BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
			ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
			constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
		}
		else {
			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(BasePackages.class);
			beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			registry.registerBeanDefinition(BEAN, beanDefinition);
		}
	}

通过断点,查看packageNames参数的传入值:

可见是在启动类中配置的scanBasePackages属性的包。

程序进入了else条件块儿,执行如下代码:

java 复制代码
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(BasePackages.class);
			beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
			beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
			registry.registerBeanDefinition(BEAN, beanDefinition);

该步骤就是创建BeanDefinition对象,然后将其注册到BeanDefinition注册器中,详情如下:

可以看到,这个BeanDefinition封装的是一个Package对象。所以,BeanDefinition不只能封装类的属性,还可以封装整个包的属性。
@Import(AutoConfigurationImportSelector.class):

进入AutoConfigurationImportSelector类:

AutoConfigurationImportSelector 是自动配置的关键类。其主要功能是选择需要导入的自动配置类。

1.选择配置类:通过 selectImports() 方法确定需要导入的自动配置类。

2.加载配置条目:调用 getAutoConfigurationEntry() 方法来加载自动配置类的元数据。

集合configurations长度为145,所以共有145个配置类可以选择,在使用时返回对应需要的配置类

3.解析配置类:通过 getCandidateConfigurations() 方法从 spring.factories 文件中加载所有可用的自动配置类,源码如下:

java 复制代码
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = new ArrayList<>(
				SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
		ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add);
		Assert.notEmpty(configurations,
				"No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
						+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

我们进入到getCandidateConfigurations()方法中可以看到是使用SpringFactoriesLoader从spring.factories文件中加载指定类型的工厂类名,然后通过ImportCandidates.load方法加载所有AutoConfiguration类,并将这些类名添加到列表中。

SpringFactoriesLoader详解

SpringFactoriesLoader属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories加载配置,源码如下:

它配合@EnableAutoConfiguration使用的话,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的Key,获取对应的一组@Configuration类

所以,@EnableAutoConfiguration自动配置:从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。

总结:

Spring Boot 的自动配置机制凭借 @EnableAutoConfiguration 注解与 AutoConfigurationImportSelector 类,达成了对 spring.factories 文件里所定义的自动配置类的智能化加载。此机制使开发者能够将精力集中于业务逻辑,无需在基础框架配置上耗费过多心思,大幅提升了开发效率,增强了代码的可维护性。

经由本文的阐述,您应当能够更透彻地领会 Spring Boot 自动配置隐藏在背后的技术要点,并且能够更为高效地运用这一特性来搭建自身的应用。

相关推荐
天使day2 分钟前
Maven
java·maven
汇匠源4 分钟前
共享无人系统,从出行到生活全面覆盖
java·生活
好开心3332 分钟前
axios的使用
开发语言·前端·javascript·前端框架·html
又蓝1 小时前
使用 Python 操作 Excel 表格
开发语言·python·excel
小灰灰要减肥1 小时前
装饰者模式
java
张铁铁是个小胖子1 小时前
MyBatis学习
java·学习·mybatis
余~~185381628001 小时前
稳定的碰一碰发视频、碰一碰矩阵源码技术开发,支持OEM
开发语言·人工智能·python·音视频
Am心若依旧4092 小时前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
明月看潮生2 小时前
青少年编程与数学 02-004 Go语言Web编程 20课题、单元测试
开发语言·青少年编程·单元测试·编程与数学·goweb
Yan.love2 小时前
开发场景中Java 集合的最佳选择
java·数据结构·链表