Spring Boot 自动装配原理及 Starter 实现原理解析
作者:Jerry.ZZZ
1、Situation
传统 Spring 引入依赖时需要用 XML 或 Java 显式配置,非常繁琐。
2、Target
方便快捷地引入依赖或者配置属性。
3、Action
3.1 @SpringBootApplication源码解析
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { @AliasFor(annotation = EnableAutoConfiguration.class) Class<?>[] exclude() default {}; @AliasFor(annotation = EnableAutoConfiguration.class) String[] excludeName() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses") Class<?>[] scanBasePackageClasses() default {}; @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator") Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; } -------------------------------------------------------- @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration { @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods() default true; } ------------------------------------------------------- @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
主要有SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解构成。
- ComponentScan 注解的作用是扫描启动类所在的包以及子包所有Bean组件并注册到 IOC 容器中,其中 excludeFilters 指定了一个过滤器列表,通过两个过滤器排除某些类,比如我们可以继承 TypeExcludeFilter 并重写 match 方法来自定义给排除哪些类。
- SpringConfiguration 注解的作用就是标记 SpringBoot 启动类为一个配置类。
- EnableAutoConfiguration 是实现自动装配的核心注解,通过@Import 注解导入 AutoConfigurationImportSelector 类
3.2 AutoConfigurationImportSelector 源码
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { //1.判断自动装配开关是否打开 if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } //2.获取所有需要装配的bean AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { //1.再次判断自动装配开关是否打开 if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } //2.获取EnableAutoConfiguration注解中的 exclude 和 excludeName AnnotationAttributes attributes = getAttributes(annotationMetadata); //3.获取需要自动装配的所有配置类,读取META-INF/spring.factories //(不止读取当前项目中的META-INF文件,所有的依赖中的META-INF文件都会被读取) List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); //4.删除重复依赖、过滤 exclude 的依赖 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); } ... } ------------------------------------------------------ public interface DeferredImportSelector extends ImportSelector { } ------------------------------------------------------- public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
AutoConfigurationImportSelector 实现了 ImportSelector 的selectImports 方法,顾名思义就是筛选引入的依赖,那么就需要加载所有的依赖,以及条件,再根据条件对依赖进行筛选。
4、Result
通过 Spring Boot 启动类上的 @SpringBootApplication 注解,Spring 就可以遍历所有 META-INF 的 spring.factories 文件中的配置类,并根据 @EnableAutoConfiguration 的条件选择是否将其注册为 bean。
5、面试回答
启动类的@SpringBootApplication注解由@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三个注解组成,三个注解共同完成自动装配;
- @SpringBootConfiguration 注解标记启动类为配置类
- @ComponentScan 注解实现启动时扫描启动类所在的包以及子包下所有标记为bean的类由IOC容器注册为bean
- @EnableAutoConfiguration 通过 @Import 注解导入
- AutoConfigurationImportSelector类,然后通过AutoConfigurationImportSelector 类的 selectImports
- 方法去读取需要被自动装配的组件依赖下的spring.factories文件配置的组件的类全名,并按照一定的规则过滤掉不符合要求的组件的类全名,将剩余读取到的各个组件的类全名集合返回给IOC容器并将这些组件注册为bean。
6、实现 Starter 的步骤
创建 Spring Boot 工程,添加项目需要的依赖,Spring Configuration Processor 这个依赖可以帮助开发者自动生成配置的的代码提示。
删除 pom.xml 的 build 部分
创建 Config 文件
在 resources 文件夹下新建 META-INF 文件夹,然后新建 spring.factories 文件,编写配置项为自动引入配置的类。
之后可以对这个项目打包,在其他的项目中通过pom.xml文件的坐标引入这个项目
在 AutoConfigurationImportSelector 中也可以发现com.example.demo.DemoConfiguration 类已经被成功加载了。
到此这篇关于Spring Boot 自动装配原理及 Starter 实现的文章就介绍到这了,更多相关Spring Boot 自动装配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!