springboot自动配置原理(个人笔记)

138 阅读3分钟

自动配置源码解析:

  1. 项目启动
  2. 加载所有jar包下 META-INF/spring.factories 文件, 保存在map中,包含了所有的自动配置类 ctrl+n搜索类 ctrl+F12展示所有方法
//spring工厂加载器
public final class SpringFactoriesLoader {

    //SpringFactoriesLoader类中的常量FACTORIES_RESOURCE_LOCATION定义了读取文件路径
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
    //加载所有jar包下 META-INF/spring.factories 文件,保存在map中
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	try {
            //classLoader: 一个类加载器
            //三元表达式对classLoader进行滤空
            Enumeration<URL> urls = (classLoader != null ?
                    //不为空,加载需要的资源文件,前面常量定义的路径下的文件
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION):
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            result = new LinkedMultiValueMap<>();
            //在所有jar包下寻找spring.factories文件
            while (urls.hasMoreElements()) {
		URL url = urls.nextElement();
		UrlResource resource = new UrlResource(url);
                //通过刚刚找到的spring.factories文件路径解析文件,将结果存入result
		Properties properties = PropertiesLoaderUtils.loadProperties(resource);
		for (Map.Entry<?, ?> entry : properties.entrySet()) {
                    String factoryTypeName = ((String) entry.getKey()).trim();
                    for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
			result.add(factoryTypeName, factoryImplementationName.trim());
                    }
                }
            }
            //将找到的自动配置类缓存进catch map
            cache.put(classLoader, result);
            return result;
	}
	catch (IOException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
    }
}

项目中所有的jar包 image.png 找到一个spring.factories文件 image.png 将所有spring.factories的配置进行合并,作为键值对,存入map,我们比较关注"org.springframework.boot.autoconfigure.EnableAutoConfiguration=
"里的内容,这个key下的类都是自动配置类,org.springframework.boot.autoconfigure是springboot自动配置最核心的包 image.png result就是最后生成的那个map(注意,这里一共有130个自动配置类,但不是每一个都需要自动配置) image.png 只有满足条件的自动配置类才会被自动配置 image.png

  1. 获取候选配置类,根据条件过滤掉不满足条件的配置类

    AutoConfiguration自动导入;Import导入;Selector过滤;

    调用 AutoConfigurationImportSelector类的getAutoConfigurationEntry()方法

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   //获取候选配置,也就是刚刚缓存的130个自动配置(调用过程见图)
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   //获取到自动配置类
   configurations = removeDuplicates(configurations);
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
   //"filter",过滤掉不需要的自动配置类
   configurations = getConfigurationClassFilter().filter(configurations);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations()调用SpringFactoriesLoader.loadFactoryNames() image.png loadFactoryNames()调用loadSpringFactories() image.png loadSpringFactories()刚刚已经执行过了,这里获取缓存进去的数据并返回 image.png 获取到自动配置类 image.png 过滤之后留下的自动配置类 image.png 类实现自动配置步骤

  1. 标注当前类是配置类
  2. 条件:导入了相关依赖 -> @ConditionalOnClass
  • ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean,也就是有没有导入对应的jar包
  • ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean
  • ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean
  1. 读取配置 -> @EnableConfigurationProperties -> 配置类加载配置
  2. 创建bean对象加入到IOC容器 @Bean

image.png

image.png

自动配置三要素

  1. 哪些类是用于实现自动配置
    • META-INF/spring.factories文件中自动配置化的类(org.springframework.boot.autoconfigure.EnableAutoConfiguration=\下的类)
  2. 哪些自动配置类会进行自动配置
    • 满足了@conditional条件的自动配置类
  3. 什么时候开启的自动配置功能
    • 自动配置不是默认开启的,需要添加一个注解 @EnableAutoConfiguration

自动装配

启动类上有一个@SpringBootApplication注解 image.png @SpringBootApplication里还有三个注解 image.png

  • @SpringBootConfiguration : 表示当前类具备配置类的功能 image.png
  • @EnableAutoConfiguration :开启自动配置
    • @AutoConfigurationPackage:自动注册的包(自己工程的自动装配)
    • @Import(AutoConfigurationImportSelector.class)(第三方工程的自动装配) @AutoConfigurationPackage-@Import(AutoConfigurationPackages.Registrar.class)Registrar() image.png Registrar() image.png @Import(AutoConfigurationImportSelector.class)加载类中的getAutoConfigurationEntry方法,与前文串联 image.png
  • @ComponentScan : 组件扫描,加入到IOC容器里

自动配置流程梳理

  1. 项目启动时,SpringFactoriesLoader类调用loadSpringFactories()方法获取META-INF/spring.factories文件中配置好的的自动配置类
  2. 启动类的SpringBootApplication注解下的EnableAutoConfiguration注解开启自动配置,EnableAutoConfiguration下的AutoConfigurationPackage加载springboot提供的自动配置类,@Import(AutoConfigurationImportSelector.class)装配第三方的自动配置类
  3. AutoConfigurationImportSelector类中的getAutoConfigurationEntry()方法去调用loadSpringFactories()方法获取缓存好的自动配置类,并进行过滤,留下需要的自动配置类 4.自动配置类需要满足的条件
  • @configuration:配置类
  • @conditional:是否自动配置的条件
  • @EnableConfigurationProperties:读取配置
  • @Bean:放入ioc容器