栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot自动装配原理详细讲解(清楚 明白)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot自动装配原理详细讲解(清楚 明白)

注意看代码加的中的注解

1.启动类上因为加上了 @EnableEurekaServer这个注解 才可以实现自动装配

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

2.自动装配的核心方法 loadSpringFactories()

    protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {

// 注意这点 loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) 方法

        List 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;
    }


public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

// 注意这点 loadSpringFactories方法

        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {

// 这点才是真正从文件中加载需要自动装配类的业务逻辑
                Enumeration urls = classLoader != null ? classLoader.getResources("meta-INF/spring.factories") : ClassLoader.getSystemResources("meta-INF/spring.factories");
                linkedMultiValueMap result = new linkedMultiValueMap();
// 省略
。。。。。。。。。。。。。。。

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [meta-INF/spring.factories]", var13);
            }
        }
    }

3.loadFactoryNames()方法

注意这个方法是进入从meta-INF/spring.factories文件下加载需要自动装配类的核心方法,但是这个方法会被调用很多次,比如:

1>  SpringApplication.run(EurekaApplication.class) 中进入loadFactoryNames

//1. 进入 SpringApplication的构造方法中
SpringApplication.run(EurekaApplication.class) 

// 2. 注意getSpringFactoriesInstances()方法
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
      
    // 。。。 省略   
    // 光这里就调用了 getSpringFactoriesInstances()方法两次 但注意这里传入的参数类型不同 
// 下面会用到这点差异
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

//3.再次进入到  pringFactoriesLoader.loadFactoryNames(type, classLoader)方法
// 注意看loadFactoryNames方法每次传入一个type
//光上次在构造函数中就传过来两个不同的类型 ApplicationContextInitializer.class
// 分别是 1> ApplicationListener.class 2>

private  Collection getSpringFactoriesInstances(Class type) {
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }

// 再次进入到  pringFactoriesLoader.loadFactoryNames(type, classLoader)方法
    private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set names = new linkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// ....
        return instances;
    }

2>通过@SpringBootApplication注解进入loadFactoryNames方法

// 1.进入@SpringBootApplication 注解
@Target({ElementType.TYPE})
//..
@SpringBootConfiguration
@EnableAutoConfiguration
// ....
)
public @interface SpringBootApplication {
  // ....
}

// 2. 进入到@EnableAutoConfiguration注解
// 在这个注解里看到了 熟悉的@import注解 
// 自动注入就是通过这个注解对配置了@Configure的自动装配类进行自动注入的

//...
@import({AutoConfigurationimportSelector.class})
public @interface EnableAutoConfiguration {
//...
}

// 3. 进入 AutoConfigurationimportSelector类
// 直接看 核心方法 selectimports

  public String[] selectimports(Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return NO_importS;
        } else {
            AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader.loadmetadata(this.beanClassLoader);
            AutoConfigurationimportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationmetadata, annotationmetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }


protected AutoConfigurationimportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationmetadata autoConfigurationmetadata, Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return EMPTY_ENTRY;
        } else {
       //...
// 注意这个方法  getCandidateConfigurations(annotationmetadata, attributes);
            List configurations = this.getCandidateConfigurations(annotationmetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set exclusions = this.getExclusions(annotationmetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationmetadata);
            this.fireAutoConfigurationimportEvents(configurations, exclusions);
            return new AutoConfigurationimportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }


// 4.进入 getCandidateConfigurations方法

  protected List getCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
// 在这里看以看到 这里通过 this.getSpringFactoriesLoaderFactoryClass()获得类的类型 传入
// loadFactoryNames方法中 
        List 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;
    }

到这里就展示了两种进入loadFactoryNames方法的途径,接下来解析这个方法:

a.可以看到这行代码,每次根据传入到loadFactoryNames方法里的类的类型获得类的全限定类名

String factoryClassName = factoryClass.getName(); 
  
 public static List loadFactoryNames(Class factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

b.loadSpringFactories方法从meta-INF/spring.factories加载需要装配的类

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration urls = classLoader != null ? classLoader.getResources("meta-INF/spring.factories") : ClassLoader.getSystemResources("meta-INF/spring.factories");
                linkedMultiValueMap result = new linkedMultiValueMap();

                while(urls.hasMoreElements()) {
    
                }

                cache.put(classLoader, result);
                return result;
// 看下面debug 结果 result得到39种类型 
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [meta-INF/spring.factories]", var13);
            }
        }
    }

spring-boot-autoconfigure-2.1.4.RELEASE.jarmeta-INFspring.factories 下面只有6种类型,在其它包下的meta-INFspring.factories一定还有对应的33种

 点开 EnableAutoConfiguration可以发现, 这242个才是SpringBoot提供的所有自动装配的类文件

再根据这个方法,我们可以知道 先获得factoryClass的名字,也就是那39个类的名字,然后根据这个名字去获得下面对应的类文件,所以可知当我们需要EnableAutoConfiguration的类时,根据它的名字去result中直接加载,SpringBoot只在第一次调用LoadFactoryNames方法时去spring.factories文件下扫描到result中存储,下次再访问时就不会再扫描磁盘,而是根据类的名字获取下面所有的类了,看下面这个判断:

if (result != null) {
    return result;
} else {
    try {

4.上面从meta-INFspring.factories文件加载类的逻辑说清楚后,再看@import获得自动装配类的逻辑

  protected AutoConfigurationimportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationmetadata autoConfigurationmetadata, Annotationmetadata annotationmetadata) {
        if (!this.isEnabled(annotationmetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationmetadata);

// 根据 org.springframework.boot.autoconfigure.EnableAutoConfiguration 这个类的名字
// 获得下面SpringBoot提供的242个可以自动装配的类
            List configurations = this.getCandidateConfigurations(annotationmetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set exclusions = this.getExclusions(annotationmetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
// 这里通过
// org.springframework.boot.autoconfigure.condition.OnBeanCondition,
// org.springframework.boot.autoconfigure.condition.OnClassCondition,
// org.springframework.boot.autoconfigure.condition.onWebApplicationCondition
// 这三个类对这242个类进行过滤 也就是@Condition注解 filiter 里面是具体的逻辑
// 过滤后返回 通过@importSelector即可自动创建对象到IOC
            configurations = this.filter(configurations, autoConfigurationmetadata);
            this.fireAutoConfigurationimportEvents(configurations, exclusions);
            return new AutoConfigurationimportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/782031.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号