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

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

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

1723956831160

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

一、@SpringBootConfiguration注解

内部结构:

1723956978015

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

进入内部:

1723957021487

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

二、@EnableAutoConfiguration注解

内部结构:

1723957221490

@AutoConfigurationPackage注解:

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

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

源码如下:

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方法:

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参数的传入值:

1723957491816

可见是在启动类中配置的scanBasePackages属性的包。
程序进入了else条件块儿,执行如下代码:

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

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

1723957712367

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

进入AutoConfigurationImportSelector类:

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

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

1723959187034

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

1723959241908

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

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

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加载配置,源码如下:

1723958420241

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

1723958497146

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

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值