我是靠谱客的博主 甜美棒棒糖,最近开发中收集的这篇文章主要介绍SpringBoot自动装配原理详细讲解(清楚 明白),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

注意看代码加的中的注解

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


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

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

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

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

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


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

// 注意这点 loadSpringFactories方法

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

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

// 这点才是真正从文件中加载需要自动装配类的业务逻辑
                Enumeration<URL> 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 <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }

// 再次进入到  pringFactoriesLoader.loadFactoryNames(type, classLoader)方法
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> 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<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.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }


// 4.进入 getCandidateConfigurations方法

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

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

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

String factoryClassName = factoryClass.getName(); 
  
 public static List<String> 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<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                Enumeration<URL> 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<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> 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);
        }
    }

最后

以上就是甜美棒棒糖为你收集整理的SpringBoot自动装配原理详细讲解(清楚 明白)的全部内容,希望文章能够帮你解决SpringBoot自动装配原理详细讲解(清楚 明白)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(47)

评论列表共有 0 条评论

立即
投稿
返回
顶部