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