《深入探究 @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 自动配置隐藏在背后的技术要点,并且能够更为高效地运用这一特性来搭建自身的应用。

相关推荐
无心水几秒前
Python时间处理通关指南:datetime/arrow/pandas实战
开发语言·人工智能·python·pandas·datetime·arrow·金融科技
华科易迅1 分钟前
Spring AOP(XML后置+异常通知)
xml·java·spring
2301_810160951 分钟前
C++与Docker集成开发
开发语言·c++·算法
jgbazsh2 分钟前
Spring中把一个bean对象交给Spring容器管理的三种方式
java·后端·spring
wjs20243 分钟前
PHP MySQL 使用 Order By 排序
开发语言
CSDN_Colinw3 分钟前
C++模块化设计原则
开发语言·c++·算法
Network porter4 分钟前
IDEA2025(2025.2)都更新了什么???
java·intellij-idea·idea
草原上唱山歌5 分钟前
如何理解C语言中的指针?
c语言·开发语言·数据结构
m0_662577976 分钟前
C++中的模板方法模式
开发语言·c++·算法
twc8296 分钟前
不可言说的知识:AI时代软件工程的核心传递问题
java·人工智能·大模型·软件工程·知识工程