SpringBoot自动装配原理及分析

一、什么是自动装配

在使用SpringBoot的时候,会自动将Bean装配到IoC容器中。例如我们在使用Redis数据库的时候,会引入依赖spring-boot-starter-data-redis。在引入这个依赖后,服务初始化的时候,会将操作Redis需要的组件注入到IoC容器中进行后续使用

自动装配大致过程如下:

  • 获取到组件(例如spring-boot-starter-data-redis)META-INF文件夹下的spring.factories文件
  • spring.factories文件中列出需要注入IoC容器的类
  • 将实体类注入到IoC容器中进行使用

二、自动装配原理

自动装配大致流程是通过@SpringBootApplication进行实现,这个注解声明在SpringBoot的启动类上

1、SpringBoot启动类

@SpringBootApplication
public class SampleSpringApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleSpringApplication.class, args);
    }
}

2、@SpringBootApplication注解

SpringBoot启动类=>@SpringBootApplication

@Target({ElementType.TYPE})//该注解作用于接口、类、枚举
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后仍然存在
@Documented//有了该注释后,如果有接口使用了该注解,生成的javadoc文件中,会把该注解展示出来
@Inherited//如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
@SpringBootConfiguration//标识它是一个SpringBoot配置类
@EnableAutoConfiguration//主要是通过这个注解实现自动装配
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })//配置类上添加@ComponentScan注解,该注解默认会扫描该类所在的包下所有的配置类
public @interface SpringBootApplication { ... }

3、@SpringBootConfiguration注解

SpringBoot启动类=>@SpringBootApplication=>@SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

通过@SpringBootConfiguration注解标识SpringBootApplication是一个SpringBoot配置类

@AliasFor注解用于为注解属性声明别名(@SpringBootApplication注解也有@AliasFor注解)

4、@EnableAutoConfiguration注解

SpringBoot启动类=>@SpringBootApplication=>@EnableAutoConfiguration

@Target({ElementType.TYPE})//该注解作用于接口、类、枚举
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后仍然存在
@Documented//有了该注释后,如果有接口使用了该注解,生成的javadoc文件中,会把该注解展示出来
@Inherited//如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
@AutoConfigurationPackage//将添加该注解的类所在的package作为自动配置package进行管理
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

	String[] excludeName() default {};

}

通过@EnableAutoConfiguration注解实现自动装配

5、@AutoConfigurationPackage注解

SpringBoot启动类=>@SpringBootApplication=>@EnableAutoConfiguration=>@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

}

通过@AutoConfigurationPackage注解将添加该注解的类所在的package作为自动配置package进行管理

通过AutoConfigurationPackages工具类获取自动配置package列表,也就是说当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package

6、@EnableAutoConfiguration注解最重要的是AutoConfigurationImportSelector.class,将需要装配的类装配到IoC容器中,下面重点分析一下这个类的实现

三、核心类分析

1、selectImport方法

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

AutoConfigurationImportSelector中的selectImport方法是自动装配的核心实现,它主要是读取META-INF/spring.factories文件,经过去重、过滤,返回需要装配的配置类集合

2、getAutoConfigurationEntry方法

selectImport方法=>getAutoConfigurationEntry方法

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);
}
  • getAttributes方法:获取@EnableAutoConfiguration中的exclude、excludeName等
  • getCandidateConfigurations方法:获取所有自动装配的配置类,也就是读取spring.factories文件,后面会再次说明
  • removeDuplicates方法:去除重复的配置项
  • getExclusions方法:根据@EnableAutoConfiguration中的exclude、excludeName移除不需要的配置类
  • fireAutoConfigurationImportEvents方法:广播事件
  • 最后根据多次过滤、判重返回配置类合集

3、getCandidateConfigurations方法

selectImport方法=>getAutoConfigurationEntry方法=>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;
}

通过loadFactoryNames方法,扫描classpath下的META-INF/spring.factories文件,里面是以key=value形式存储,读取其中key=EnableAutoConfiguration,value就是需要装配的配置类,也就是getCandidateConfigurations返回的值

四、总结

1)通过注解@SpringBootApplication=>@EnableAutoConfiguration=>@Import({AutoConfigurationImportSelector.class})实现自动装配

2)AutoConfigurationImportSelector类中重写了ImportSelector中selectImports方法,批量返回需要装配的配置类

3)通过Spring提供的SpringFactoriesLoader机制,扫描classpath下的META-INF/spring.factories文件,读取需要自动装配的配置类

4)依据条件筛选的方式,把不符合的配置类移除掉,最终完成自动装配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

z.haoui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值