@EnableAutoConfiguration分析

自动配置作用

spring框架的底层注解,它的作用就是给容器中导入某个组件类

  • @Import(AutoConfigurationImportSelector.class)�(导入组件的具体方式)
  • @AutoConfigurationPackage� 自动配置的扫描包

加载配置文件META-INF/spring-autoconfigure-metadata.properties,从中获取所有支持自动配置类的条件
作用:SpringBoot使用一个Annotation的处理器来收集一些自动装配的条件,那么这些条件可以在META-INF/spring-autoconfigure-metadata.properties进行配置。
SpringBoot会将收集好的@Configuration进行一次过滤进而剔除不满足条件的配置类
自动配置的类全名.条件=值

@EnableAutoConfiguration就是从classpath中搜寻META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置项通过反射(Java Reflection)实例化为对应的标注了@Configuration的JavaConfig形式的配置类,并加载到IoC容器中。
直到看到了spring.factories配置文件对应的那些类才明白了Spring Boot为啥不需要配置各种XML文件了。那是因为这些配置类的本质是传统Spring MVC框架中对应的XML配置文件,只不过在Spring Boot中以自动配置类的形式进行了预先配置。

直接分析

前面看了那么多,当解析启动类的时候,会走到这里

直接看AutoConfigurationGroup#process方法
还是要强调一下 springBoot 这里直接不走selectImports
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup#process

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {


    /*
    	这块逻辑默认不会走到,走的是下面内部类:AutoConfigurationGroup#selectImports
    */
    @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());
    }

    private static class AutoConfigurationGroup
    implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
        // ...

        @Override
        public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
            // 判断一下@Import中的类是否是 AutoConfigurationImportSelector ,因为下一步要强转
            // 但是个人感觉这一步判断有点多余,可能这里只是为了输出日志
            Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
                         () -> String.format("Only %s implementations are supported, got %s",
                                             AutoConfigurationImportSelector.class.getSimpleName(),
                                             deferredImportSelector.getClass().getName()));
            /*
            核心代码在这里:
            getAutoConfigurationMetadata() 加载配置文件META-INF/spring-autoconfigure-metadata.properties
            */
            AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
            this.autoConfigurationEntries.add(autoConfigurationEntry);
            for (String importClassName : autoConfigurationEntry.getConfigurations()) {
                this.entries.putIfAbsent(importClassName, annotationMetadata);
            }
        }

        @Override
        public Iterable<Entry> selectImports() {
            if (this.autoConfigurationEntries.isEmpty()) {
                return Collections.emptyList();
            }
            Set<String> allExclusions = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
            Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
            .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
            .collect(Collectors.toCollection(LinkedHashSet::new));
            processedConfigurations.removeAll(allExclusions);

            return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
            .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
            .collect(Collectors.toList());
        }

        private AutoConfigurationMetadata getAutoConfigurationMetadata() {
            if (this.autoConfigurationMetadata == null) {
                this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            }
            return this.autoConfigurationMetadata;
        }

        private List<String> sortAutoConfigurations(Set<String> configurations,
                                                    AutoConfigurationMetadata autoConfigurationMetadata) {
            return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata)
            .getInPriorityOrder(configurations);
        }

        private MetadataReaderFactory getMetadataReaderFactory() {
            try {
                return this.beanFactory.getBean(SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,
                                                MetadataReaderFactory.class);
            }
            catch (NoSuchBeanDefinitionException ex) {
                return new CachingMetadataReaderFactory(this.resourceLoader);
            }
        }

    }

    
    private AutoConfigurationMetadata getAutoConfigurationMetadata() {
			if (this.autoConfigurationMetadata == null) {
                // 初始化自动配置元数据
				this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
			}
			return this.autoConfigurationMetadata;
		}
}

扫描自动配置类元数据属性值

META-INF/spring-autoconfigure-metadata.properties :

# 内容格式 (自动配置的类全名.条件Condition=值)
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration.ConditionalOnClass=com.rabbitmq.client.Channel,org.springframework.amqp.rabbit.core.RabbitTemplate


org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader#loadMetadata(java.lang.ClassLoader)

final class AutoConfigurationMetadataLoader {
	// 默认的扫描自动注入的路径
	protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties";

	private AutoConfigurationMetadataLoader() {
	}

	static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
		return loadMetadata(classLoader, PATH);
	}

	static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
		try {
            // 读取spring-boot-autoconfigure-2.2.3.RELEASE.jar包中spring-autoconfigure-metadata.properties的信息生成urls枚举对象
			Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
					: ClassLoader.getSystemResources(path);
			Properties properties = new Properties();
			while (urls.hasMoreElements()) {
                // 解析每一个元素解析为 java.util.Properties
                // 这里的解析通过
				properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
			}
			return loadMetadata(properties);
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
		}
	}

	static AutoConfigurationMetadata loadMetadata(Properties properties) {
		return new PropertiesAutoConfigurationMetadata(properties);
	}

}

	public static Properties loadProperties(Resource resource) throws IOException {
		Properties props = new Properties();
		fillProperties(props, resource);
		return props;
	}

	public static void fillProperties(Properties props, Resource resource) throws IOException {
		InputStream is = resource.getInputStream();
		try {
			String filename = resource.getFilename();
			if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
				props.loadFromXML(is);
			}
			else {
                // 通过inStream 解析出 .properties 文件中的格式
				props.load(is);
			}
		}
		finally {
			is.close();
		}
	}

扫描自动配置类

扫描 META-INF/spring.factories 文件
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                                           AnnotationMetadata annotationMetadata) {
    // 这里是一层校验,校验是否存在注解 @EnableAutoConfiguration
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }

    // 获取注解的属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);

    // 扫描 META-INF/spring.factories 文件
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去重
    configurations = removeDuplicates(configurations);
    // 校验对无效的排除类异常抛出
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    // 排除Exclusions
    configurations.removeAll(exclusions);
    // 过滤-配置类生效的方式

    /*
    但是这里这过滤三个分别是 为什么就这三个呢,参考下面这个图片
    @ConditionalOnClass、
    @ConditionalOnWebApplication
    @ConditionalOnBean或者@ConditionalOnSingleCandidate
    注意这里的 @ConditionalOnBean 校验是的 spring-autoconfigure-metadata.properties 里面的bean在当前类加载器中存在,
    校验并不是spring里面的bean是否存在,这里区别其他地方的使用
    
    */
    configurations = filter(configurations, autoConfigurationMetadata);
    // 将配置类和排除类放进监听器
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}

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;
	}
	public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
		String factoryTypeName = factoryType.getName();
		return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
	}

org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
    	// 只加载一次,再来读缓存
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
                // 解析为Properties
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                // 格式转换
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
                    /*
                    factoryTypeName = a
                    entry.getValue() = 1,2,3
                    ====》  Map<String, List<String>> 格式
                    ====》  {"b":["1","2","3"]} 
                    */
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

filter

org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition

abstract class FilteringSpringBootCondition {
    private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
        long startTime = System.nanoTime();
        // 每一个候选配置
        String[] candidates = StringUtils.toStringArray(configurations);
        // 标记每一个候选的配置 true-不跳过,false-跳过
        boolean[] skip = new boolean[candidates.length];
        boolean skipped = false;
        for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
            invokeAwareMethods(filter);
            boolean[] match = filter.match(candidates, autoConfigurationMetadata);
            for (int i = 0; i < match.length; i++) {
                if (!match[i]) {
                    skip[i] = true;
                    candidates[i] = null;
                    // 有一个满足条件就是可以
                    skipped = true;
                }
            }
        }
        if (!skipped) {
            return configurations;
        }
        List<String> result = new ArrayList<>(candidates.length);
        for (int i = 0; i < candidates.length; i++) {
            if (!skip[i]) {
                // 把过滤条件符合的给找出来
                result.add(candidates[i]);
            }
        }
        if (logger.isTraceEnabled()) {
            int numberFiltered = configurations.size() - result.size();
            logger.trace("Filtered " + numberFiltered + " auto configuration class in "
                         + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
        }
        return new ArrayList<>(result);
    }

    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
        /*
         这里有三个实现类:OnBeanCondition、OnClassCondition、OnWebApplicationCondition
        */
        ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
        boolean[] match = new boolean[outcomes.length];
        for (int i = 0; i < outcomes.length; i++) {
            match[i] = (outcomes[i] == null || outcomes[i].isMatch());
            if (!match[i] && outcomes[i] != null) {
                logOutcome(autoConfigurationClasses[i], outcomes[i]);
                if (report != null) {
                    report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
                }
            }
        }
        return match;
    }
}

getAutoConfigurationImportFilters

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationImportFilters
image.png

filter的底层逻辑

OnBeanCondition.getOutcomes

以 【org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration】为例分析
org.springframework.boot.autoconfigure.condition.OnBeanCondition#getOutcomes
image.png

@Override
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
                                               AutoConfigurationMetadata autoConfigurationMetadata) {
    ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
    for (int i = 0; i < outcomes.length; i++) {
        String autoConfigurationClass = autoConfigurationClasses[i];
        if (autoConfigurationClass != null) {
            /*
                底层是这个:
                this.properties.getProperty(className + "." + key);
                this.properties 指的是META-INF/spring-autoconfigure-metadata.properties文件
                org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.ConditionalOnBean=org.springframework.cache.interceptor.CacheAspectSupport

                最终取值:org.springframework.cache.interceptor.CacheAspectSupport
                */
            Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");
            // 解析onBeanTypes是否存在
            outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
            if (outcomes[i] == null) {
                Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,
                                                                                      "ConditionalOnSingleCandidate");
                outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);
            }
        }
    }
    return outcomes;
}


private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
   // 这里的filter是FilteringSpringBootCondition.filter
    List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
    if (!missing.isEmpty()) {
        ConditionMessage message = ConditionMessage.forCondition(annotation)
        .didNotFind("required type", "required types").items(Style.QUOTE, missing);
        return ConditionOutcome.noMatch(message);
    }
    return null;
}

org.springframework.boot.autoconfigure.condition.FilteringSpringBootCondition#filter

protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
			ClassLoader classLoader) {
		if (CollectionUtils.isEmpty(classNames)) {
			return Collections.emptyList();
		}
		List<String> matches = new ArrayList<>(classNames.size());
		for (String candidate : classNames) {
            // 然后这段代码比较简单不再细看,就是用当前classLoader看一下当前类是否存在
			if (classNameFilter.matches(candidate, classLoader)) {
				matches.add(candidate);
			}
		}
		return matches;
	}

OnClassCondition.getOutcomes

**这里的逻辑值得思考?**主线程等待子线程执行的方法借鉴

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {

	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		// Split the work and perform half in a background thread if more than one
		// processor is available. Using a single additional thread seems to offer the
		// best performance. More threads make things worse.
        // 如果当前机器是多线程
		if (Runtime.getRuntime().availableProcessors() > 1) {
			return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);
		}
		else {
            // 单线程处理
			OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,
					autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
			return outcomesResolver.resolveOutcomes();
		}
	}
}
	private ConditionOutcome[] resolveOutcomesThreaded(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
        // 把当前自动配置类分为俩半
		int split = autoConfigurationClasses.length / 2;
        // 一半多线程异步处理:每个autoConfigurationClasses 创建一个线程 this.thread.start();
		OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,
				autoConfigurationMetadata);
        // 一半单线程处理:
		OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,
				autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
        // 单线程遍历处理
		ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
        // 异步处理那块,子线程进入join状态, this.thread.join();
		ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];

        // 汇总结果
		System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
		System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
		return outcomes;
	}

OnWebApplicationCondition.getOutcomes
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值