Spring Boot 自动装配原理

前言

在 SpringBoot 中,我们需要使用某个依赖,直接添加一个 starter 即可。

为什么添加了一个 starter 就能生效?这其中就离不来 SpringBoot 的自动装配。

自动装配是 Starter 的基础,也是整个 Spring Boot 的核心,那什么是自动装配呢?简单来说,就是自动将 Bean 装配到 IOC 容器中这么一个操作。

自动装配是如何实现的?

先看一下 SpringBoot 的核心注解@SpringBootApplication

@Target({ElementType.TYPE}) //接口、类、枚举、注解
@Retention(RetentionPolicy.RUNTIME) //这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
@Documented // 说明该注解将被包含在javadoc中
@Inherited // 说明子类可以继承父类中的该注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
 		...
}

大概可以把 @SpringBootApplication 看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制

  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类

  • @ComponentScan: 扫描被 @Component (@Service,@Controller) 注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。

其中,@EnableAutoConfiguration 是实现自动装配的重要注解,我们以这个注解入手。

@EnableAutoConfiguration

@EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所欲组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

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

    String[] excludeName() default {};
}

AutoConfigurationImportSelector

AutoConfigurationImportSelector 类的继承体系如下:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

}

public interface DeferredImportSelector extends ImportSelector {

}

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata var1);
}

可以看出,AutoConfigurationImportSelector 类继承自 DeferredImportSelector,DeferredImportSelector 继承自 ImportSelector ,并实现了 ImportSelector 接口,也就实现了这个接口中的 selectImports 方法,该方法主要用于获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中

selectImports 方法

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

其中,getAutoConfigurationEntry 方法则是自动装配的逻辑,继续点进去。

   protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

其中 getCandidateConfigurations 继续点进去

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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 继续点进去:

 ...
 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");
      ...

能看到,是在加载 "META-INF/spring.factories" 路径下的配置类。

总结:到这里基本清楚了,springboot 的自动装配就是通过自定义实现 ImportSelector 接口,从而导致项目启动时会自动将所有项目 META-INF/spring.factories 路径下的配置类注入到 spring 容器中,从而实现了自动装配。

参考资源

1.https://www.cnblogs.com/fcb-it/p/12905525.html

2.https://zhuanlan.zhihu.com/p/345895748

每天学习一点点,每天进步一点点。

posted @ 2021-07-29 13:42  爱吃西瓜的番茄酱  阅读(472)  评论(0编辑  收藏  举报