zoukankan      html  css  js  c++  java
  • 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

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

  • 相关阅读:
    Power BI for Office 365(八)共享查询
    Power BI for Office 365(七) Power BI站点
    Power BI for Office 365(六)Power Map简介
    Power BI for Office 365(五)Power View第二部分
    Power BI for Office 365(四)Power View第一部分
    Power BI for Office 365(三)Power Pivot
    Power BI for Office 365(二)Power Query
    java 继承、重载、重写与多态
    Android 热修复方案Tinker(一) Application改造
    阿里最新热修复Sophix与QQ超级补丁和Tinker的实现与总结
  • 原文地址:https://www.cnblogs.com/youcoding/p/15074650.html
Copyright © 2011-2022 走看看