springboot源码分析-自动装配

2021/10/2 17:11:38

本文主要是介绍springboot源码分析-自动装配,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1.概述

springboot是用main方法来启动服务的,mian方法都加有 SpringBootApplication这个注解,这个注解是springboot自动装配的实现

首先看SpringBootApplication这个注解的源码

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.repository.Repository;

/**
 * 表示声明一个或多个的 {@link Configuration 配置} 类
 * {@link Bean @Bean} 方法并触发 {@link EnableAutoConfiguration
 * 自动配置},{@link ComponentScan 组件扫描},以及
 * {@link ConfigurationPropertiesScan 配置属性扫描}。这是一个
 * 相当于声明 {@code @Configuration} 的便利注解,
 * {@code @EnableAutoConfiguration}、{@code @ComponentScan} 和
 * {@code @ConfigurationPropertiesScan}。
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 * @since 1.2.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited //表示能从子类的注解中获取到父类的注解属性
@SpringBootConfiguration //注解继承了Configuration注解并且增加了开启代理的配置
@EnableAutoConfiguration //自动装配的主要实现
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)}) //扫包
@ConfigurationPropertiesScan //属性文件内容自动填充bean
public @interface SpringBootApplication {

	/**
	 * 排除特定的自动配置类,以便它们永远不会被应用。
	 *
	 * @return 要排除的类@SpringBootApplication
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	/**
	 * 排除特定的自动配置类名称,以便它们永远不会被
	 * 适用。
	 *
	 * @return 要排除的类名
	 * @since 1.3.0
	 */
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	/**
	 * 用于扫描带注释组件的基本包。使用 {@link #scanBasePackageClasses}
	 * 用于基于字符串的包名称的类型安全替代方案。
	 * <p>
	 * <strong>注意:</strong>这个设置是一个别名
	 * 仅限 {@link ComponentScan @ComponentScan}。它对 {@code @Entity} 没有影响
	 * 扫描或 Spring Data {@link Repository} 扫描。对于那些你应该添加的
	 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} 和
	 * {@code @Enable...Repositories} 注释。
	 *
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	/**
	 * {@link #scanBasePackages} 的类型安全替代方案,用于指定要使用的包
	 * 扫描带注释的组件。将扫描指定的每个类的包。
	 * <p>
	 * 考虑在每个包中创建一个特殊的无操作标记类或接口
	 * 除了被此属性引用外,没有其他用途。
	 * <p>
	 * <strong>注意:</strong>这个设置是一个别名
	 * 仅限 {@link ComponentScan @ComponentScan}。它对 {@code @Entity} 没有影响
	 * 扫描或 Spring Data {@link Repository} 扫描。对于那些你应该添加的
	 * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} 和
	 * {@code @Enable...Repositories} 注释。
	 *
	 * @return base packages to scan
	 * @since 1.3.0
	 */
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	/**
	 * 指定 {@link Bean @Bean} 方法是否应该被代理以强制执行
	 * bean 生命周期行为,例如返回共享的单例 bean 实例,即使在
	 * 在用户代码中直接调用 {@code @Bean} 方法的情况。此功能需要
	 * 方法拦截,通过运行时生成的 CGLIB 子类实现
	 * 带有限制,例如配置类及其方法不被
	 * 允许声明 {@code final}。
	 * <p>
	 * 默认为 {@code true},允许在
	 * 配置类以及对这个配置的外部调用
	 * {@code @Bean} 方法,例如来自另一个配置类。如果不需要这个
	 * 因为每个特定配置的 {@code @Bean} 方法都是
	 * 自包含并设计为容器使用、开关的普通工厂方法
	 * 将此标志设置为 {@code false} 以避免 CGLIB 子类处理。
	 * <p>
	 * 关闭bean方法拦截有效处理{@code @Bean}方法
	 * 单独像在非 {@code @Configuration} 类上声明时一样,也就是
	 * “@Bean Lite 模式”(参见 {@link Bean @Bean 的 javadoc})。因此在行为上
	 * 相当于删除 {@code @Configuration} 构造型。
	 *
	 * @return whether to proxy {@code @Bean} methods
	 * @since 2.2
	 */
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}
  • Inherited注解:表示子类能继承当前注解的属性
    
  • SpringBootConfiguration注解:父注解是Configuration,没明白和Configuration的区别
  • EnableAutoConfiguration注解:自动装配的实现
  • ComponentScan注解:扫包,如果不配置,默认扫描当前包
  • ConfigurationPropertiesScan:配置文件里的属性自动填充到bean

主要看EnableAutoConfiguration注解

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.SpringFactoriesLoader;

/**
 * 启用 Spring 应用程序上下文的自动配置,尝试猜测和
 * 配置您可能需要的bean。自动配置类通常是
 * 根据您的类路径和您定义的 bean 应用。例如,如果你
 * 在你的类路径上有 {@code tomcat-embedded.jar} 你可能想要一个
 * {@link TomcatServletWebServerFactory}(除非你已经定义了你自己的
 * {@link ServletWebServerFactory} bean)。
 * <p>
 * 使用 {@link SpringBootApplication @SpringBootApplication} 时,自动配置
 * 自动启用上下文,因此添加此注释没有
 * 附加效果。
 * <p>
 * 自动配置尝试尽可能智能,并会像您一样后退
 * 定义更多你自己的配置。您可以随时手动 {@link #exclude()} 任何
 * 您永远不想应用的配置(如果您不想应用,请使用 {@link #excludeName()}
 * 可以访问它们)。您还可以通过
 * {@code spring.autoconfigure.exclude} 属性。始终应用自动配置
 * 在注册用户定义的 bean 之后。
 * <p>
 * 用{@code @EnableAutoConfiguration}注解的类的包,
 * 通常通过 {@code @SpringBootApplication},具有特定意义,经常使用
 * 作为“默认”。例如,它会在扫描 {@code @Entity} 类时使用。
 * 一般建议您放置 {@code @EnableAutoConfiguration} (如果您是
 * 不在根包中使用 {@code @SpringBootApplication}) 以便所有子包
 * 和类可以搜索。
 * <p>
 * 自动配置类是常规 Spring {@link Configuration @Configuration}
 * 豆子。它们使用 {@link SpringFactoriesLoader} 机制(键控
 * 针对此类)。通常自动配置bean是
 * {@link Conditional @Conditional} bean(最常使用
 * {@link ConditionalOnClass @ConditionalOnClass} 和
 * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} 注释)。
 *
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @see ConditionalOnBean
 * @see ConditionalOnMissingBean
 * @see ConditionalOnClass
 * @see AutoConfigureAfter
 * @see SpringBootApplication
 * @since 1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //配置扫描包的bean,可以通过这个bean获取到扫描的包路径
@Import(AutoConfigurationImportSelector.class) //引入自动装配的配置
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * 排除特定的自动配置类,以便它们永远不会被应用。
	 *
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * 排除特定的自动配置类名称,以便它们永远不会被
	 * 适用。
	 *
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
  • AutoConfigurationPackage注解:引入一个AutoConfigurationPackages的bean,bean里有个BasePackages的静态内部类保存要扫描的包名称,可以同步AutoConfigurationPackages的get方法获取所有的扫描包的配置
  • AutoConfigurationImportSelector注解:引入所有自动配置的bean

AutoConfigurationImportSelector源码

https://blog.csdn.net/qq_39482039/article/details/120585957

AutoConfigurationImportSelector主要实现DeferredImportSelector接口,实现了getImportGroup方法返回了AutoConfigurationImportSelector中的AutoConfigurationGroup内部类,会先调用AutoConfigurationGroup内部类的process方法,来将自动配置项设置到当前类的属性中,以便selectImports方法使用

	@Override
		public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
			Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
					() -> String.format("Only %s implementations are supported, got %s",
							AutoConfigurationImportSelector.class.getSimpleName(),
							deferredImportSelector.getClass().getName()));
			//获取自动装配的配置
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

 getAutoConfigurationEntry方法获取自动装配的配置

	/**
	 * 根据 {@link AnnotationMetadata} 返回 {@link AutoConfigurationEntry}
	 * 导入 {@link Configuration @Configuration} 类。
	 *
	 * @param autoConfigurationMetadata 自动配置元数据
	 * @param annotationMetadata       配置类的注解元数据
	 * @return the auto-configurations that should be imported
	 */
	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
															   AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		//META-INF/spring.factories下获取路径是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		//去重,并可以由子类拓展
		configurations = removeDuplicates(configurations);
		//获取排除的自动配置
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		//校验配置信息是否可加载,并且不能排除自动配置信息
		checkExcludedClasses(configurations, exclusions);
		//从自动配置移除忽略的
		configurations.removeAll(exclusions);
		//通过META-INF/spring.factories下AutoConfigurationImportFilter来过滤不需要的bean.
		//也就是通过OnBeanCondition,OnClassCondition,OnWebApplicationCondition来过滤不需要的bean.
		configurations = filter(configurations, autoConfigurationMetadata);
		//执行自动装配加载的监听器
		fireAutoConfigurationImportEvents(configurations, exclusions);
		//封装到AutoConfigurationEntry并返回
		return new AutoConfigurationEntry(configurations, exclusions);
	}

 getCandidateConfigurations方法META-INF/spring.factories下获取路径是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置

/**
	 * 返回应考虑的自动配置类名称。默认情况下
	 * 此方法将使用 {@link SpringFactoriesLoader} 加载候选对象
	 * {@link #getSpringFactoriesLoaderFactoryClass()}。
	 *
	 * @param metadata   the source metadata
	 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
	 *                   attributes}
	 * @return a list of candidate configurations
	 */
	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;
	}

 removeDuplicates转为hashset去重

protected final <T> List<T> removeDuplicates(List<T> list) {
		return new ArrayList<>(new LinkedHashSet<>(list));
	}
getExclusions获取注解要排除的自动配置
/**
	 * 返回任何限制候选配置的排除项。
	 *
	 * @param metadata   the source metadata
	 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
	 *                   attributes}
	 * @return exclusions or an empty set
	 */
	protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		excluded.addAll(asList(attributes, "exclude"));
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}
checkExcludedClasses方法自动配置项必须可加载,并且排除的自动配置必须包含在当前的配置项中
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
		List<String> invalidExcludes = new ArrayList<>(exclusions.size());
		for (String exclusion : exclusions) {
			//校验是否可以加载,并且要加载的属性中不包含排除的
			if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
				invalidExcludes.add(exclusion);
			}
		}
		//如果不能加载或者自动配置里不包含排除的配置项,抛异常提示报错
		if (!invalidExcludes.isEmpty()) {
			handleInvalidExcludes(invalidExcludes);
		}
	}
filter方法通过法META-INF/spring.factories下配置的AutoConfigurationImportFilter来过滤不需要的bean
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
		long startTime = System.nanoTime();
		String[] candidates = StringUtils.toStringArray(configurations);
		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);
	}

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

 fireAutoConfigurationImportEvents方法执行META-INF/spring.factories下配置的   AutoConfigurationImportListener类型的监听器

private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
		//获取到自动配置的监听器
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
			for (AutoConfigurationImportListener listener : listeners) {
				//设置Aware
				invokeAwareMethods(listener);
				//执行监听器
				listener.onAutoConfigurationImportEvent(event);
			}
		}
	}

protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}

 

AutoConfigurationGroup中的selectImports方法会将返回的类名数组注解为bean

	@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());
		}



这篇关于springboot源码分析-自动装配的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程