SpringBoot自动配置原理简解

SpringBoot自动配置原理简解一

我们从一个SpringBoot项目中的主方法上的注解讲起。这个注解就是非常重要的@SpringBootApplication.

SpringBootApplication注解

首先看一下SpringBootApplication类的定义。

@EnableAutoConfiguration
public @interface SpringBootApplication {

SpringBootApplication 类上面也有一个很重要的注解@EnableAutoConfiguration

EnableAutoConfiguration注解

我们再来看看这个注解类的定义

@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {

这个类的作用就是开启自动配置功能。同样的,这个类上还是有一个很重要的注解@Import,这是为了导入AutoConfigurationImportSelector类。

AutoConfigurationImportSelector类

我们继续查看它的定义和部分方法

public class AutoConfigurationImportSelector implements...{
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}
}

该方法就是给容器导入一些默认配置好的组件名称。
我们看其具体实现。在这里挑一些重要的方法简单讲述一下,详细的大家可以打开源码对照的看。
getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata)里,调用List configurations = getCandidateConfigurations(annotationMetadata, attributes);我们着重看一下getCandidateConfigurations方法。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				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;
	}

在这个方法里,要分几个步骤来讲解。

  1. getSpringFactoriesLoaderFactoryClass() 的返回结果是EnableAutoConfiguration.class
  2. getBeanClassLoader() 是当前的类加载器;
  3. 而后我们继续查看SpringFactoriesLoader.loadFactoryNames方法;
 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
       String factoryClassName = factoryClass.getName();
       return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
   }
  1. 上述方法里又得继续细细来看,同学们可不能着急啊,code得一行行看才能清楚原理。
    • loadSpringFactories方法简述
      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()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    ...
      
    • 此方法的主要作用是获取项目中所有META-INF/spring.factories文件中的键值。
    • spring.factories文件中的部分内容如下:
      # Auto Configuration Import Listeners
      org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
      org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
      
      # Auto Configuration Import Filters
      org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
      org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
      org.springframework.boot.autoconfigure.condition.OnClassCondition,\
      org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
      
      # Auto Configure
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
      org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
      org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
      org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
      
    • 紧接着的 .getOrDefault(factoryClassName, Collections.emptyList()) 方法里就是得到factoryClassName对应的集合的值。
    • 而这里的factoryClassName就是我们loadFactoryNames方法的第一个参数EnableAutoConfiguration.class对应的类路径。
    • 最后的结果就显而易见就是得到了META-INF/spring.factories里EnableAutoConfiguration的值。部分值如下:
      	# Auto Configure
         	org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
         	org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
         	org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
         	org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
         	org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
      

6.因此,SpringBoot会把配置文件中所有xxxAutoConfiguration结尾的类全部自动配置加载到容器中。

结束语

至此,SpringBoot中在没有手动配置某些文件的情况下一些功能是如何自动生效的原理就大概讲述了一下。本文是个人见解,如有差错还请同学们留言指正。
下节有时间的话,我会挑一些具体的功能是如何自动配置生效的,如WebMvcAutoConfiguration等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值