springBoot自动装配原理

本文深入解析了Spring Boot的@SpringBootApplication注解,它结合了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。@EnableAutoConfiguration核心在于AutoConfigurationImportSelector,该类从META-INF/spring.factories加载自动配置类,并根据条件决定是否加载。@AutoConfigurationPackage则用于注册配置包,配合ImportBeanDefinitionRegistrar将@Configuration@Import注解的类注入IOC容器。文章还提及了@ConfigurationProperties用于外部化配置,并讨论了为何Spring Boot不会全部自动装配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

springBoot项目自动装配核心注解就是@SpringBootApplication
我们点击@SpringBootApplication这是一个复合注解里面还有三个重要的注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

@ComponentScan这个我们都知道是开启包扫描的,注入到IOC容器中(扫描的注解包括@Component} {@Repository}, {@Service}{@Autowired} or { @Controller )

我们重点说一下剩下的两个注解

@EnableAutoConfiguration

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

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

他的核心类就是AutoConfigurationImportSelector
我们看一下它定义的变量 是不是很熟悉,BeanFactory(Bean工厂),Environment(proerty JVM环境变量)
在这里插入图片描述
可以看出,AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中。
ImportSelector实现的处理方式通常与常规@Import注释相同,但是,也可以推迟选择导入,直到所有@Configuration类都已处理完毕
在这里插入图片描述
这里最重要的方法就是

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		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);
	}

我们继续看里面的getCandidateConfigurations方法

	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

这里调用 SpringFactoriesLoader.loadFactoryNames方法
使用给定的类加载器从“META-INF/spring.factories”加载给定类型的工厂实现的完全限定类名。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
总结:
1.!isEnabled(annotationMetadata)判断spring.boot.enableautoconfiguration的属性值默认设置为true,可以自己在yml文件里面设置为false
在这里插入图片描述
2. getCandidateConfigurations(annotationMetadata, attributes);
扫描获取“META-INF/spring.factories”下要加载的自动配置文件(这里是按需加载) 不懂的可以看下我另一篇文章
配置Spring Boot通过@ConditionalOnProperty来控制Configuration是否生效
3.getExclusions(annotationMetadata, attributes);
获取要排除的配置

@AutoConfigurationPackage

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

	/**
	 * Base packages that should be registered with {@link AutoConfigurationPackages}.
	 * <p>
	 * Use {@link #basePackageClasses} for a type-safe alternative to String-based package
	 * names.
	 * @return the back package names
	 * @since 2.3.0
	 */
	String[] basePackages() default {};

	/**
	 * Type-safe alternative to {@link #basePackages} for specifying the packages to be
	 * registered with {@link AutoConfigurationPackages}.
	 * <p>
	 * Consider creating a special no-op marker class or interface in each package that
	 * serves no purpose other than being referenced by this attribute.
	 * @return the base package classes
	 * @since 2.3.0
	 */
	Class<?>[] basePackageClasses() default {};

}

我们来看他的核心方法
我们可以看到他实现了ImportBeanDefinitionRegistrar接口
registerBeanDefinitions方法是扫描将@Configuration @Import注解的类注入到IOC容器中

	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
		}

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

	}

在这里插入图片描述
这里你们是不是想到了@compentscan注解不是也是用来扫描包的吗为什么还需要@AutoConfigurationPackage呢?

@compentscan和 @AutoConfigurationPackage的区别

1.@compentscan可以扫描除了根包还可以扫描其他的包但是@AutoConfigurationPackage不能

2.@compentscan和 @AutoConfigurationPackage扫描的范围不同

  • @compentscan可以扫描含有{@Component} {@Repository}, {@Service}{@Autowired}{
    @Controller )

  • @AutoConfigurationPackage是扫描带有@Configuration @Import注解的类

扩展spring yaml配置文件

以redis为例
@ConfigurationProperties
外部化配置的注释。如果要绑定和验证某些外部属性(例如从.Properties文件),请将其添加到@Configuration类中的类定义或@Bean方法中。 绑定可以通过调用带注释类上的setter来执行,如果使用@ConstructorBinding,则可以通过绑定到构造函数参数来执行。 请注意,与@Value相反,由于属性值是外部化的,所以不会计算SpEL表达式。
在这里插入图片描述
spring不会全部装配的原因
就是类似@ConditionalOnClass,@ConditionalOnMissingBean之类的注解,有兴趣的可以自己了解一下,我这里就不详细写了
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值