Bootstrap

SpringBoot源码分析(自动装配)

SpringBoot源码分析(自动装配)

一、自动装配(原理)

1、@SpringBootApplication

// 自动装配的开始
@SpringBootApplication
public class SpringDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringDemoApplication.class, args);
    }
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// @Configuration的子注解
@SpringBootConfiguration
// 开启自动装配
@EnableAutoConfiguration
// 开启扫描机制,扫描启动类所在包(但是不包含类型排除和自动配置的Filter)
@ComponentScan(excludeFilters = { 
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) 
})
public @interface SpringBootApplication {.....}

2、@EnableAutoConfiguration

package org.springframework.boot.autoconfigure;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
// 通过 @Import 引入 AutoConfigurationImportSelector 
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

3、AutoConfigurationImportSelector

ImportSelector 接口用于实现动态地选择需要被导入到容器中的配置类的逻辑。

public interface ImportSelector {

    /**
     * @param importingClassMetadata 用于描述使用了 @Import 注解的配置类的注解元数据。
     * @return 数组中的每个元素都是一个全限定类名,表示需要被导入到容器中的配置类。
     */ 
    String[] selectImports(AnnotationMetadata importingClassMetadata);

    @Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}
}

AutoConfigurationImportSelector 实现了 ImportSelector 接口,并在 selectImports 方法中根据特定的条件或逻辑来选择需要导入的配置类,实现更加灵活和动态的配置。

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

    // 这里的参数 annotationMetadata,就是 @EnableAutoConfiguration 注解的元数据
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationEntry autoConfigurationEntry = 
                // 获取自动配置类
                this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

    protected static class AutoConfigurationEntry {
        private final List<String> configurations;	// 需要导入的
        private final Set<String> exclusions;		// 不需要导入的
    }

    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        }
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 获取所有候选的配置类
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        // 去重
        configurations = removeDuplicates(configurations);
        // 排除的 configurations
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = getConfigurationClassFilter().filter(configurations);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        // 返回封装了 META-INF/spring.factories 中的自动配置类的Entry
        return new AutoConfigurationEntry(configurations, exclusions);
    }

    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        // 获取所有配置类的类全名
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            this.getSpringFactoriesLoaderFactoryClass(),	// EnableAutoConfiguration.class
            this.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;
    }

    protected Class<?> getSpringFactoriesLoaderFactoryClass() {
        return EnableAutoConfiguration.class;
    }

}

4、SpringFactoriesLoader

// org.springframework.core.io.support.SpringFactoriesLoader

/**
 * 这里的 factoryType 就是 EnableAutoConfiguration.class
 */
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
    // org.springframework.boot.autoconfigure.EnableAutoConfiguration
    String factoryTypeName = factoryType.getName();
    // 获取 META-INF/spring.factories 文件中 EnableAutoConfiguration 对应的配置类的类全名
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

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 {
            // 扫描jar包路径下的 META-INF/spring.factories 文件
            Enumeration<URL> urls = classLoader != null ? 
                classLoader.getResources("META-INF/spring.factories") : 
            ClassLoader.getSystemResources("META-INF/spring.factories");
            
            // 把 META-INF/spring.factories 解析成 Map
            MultiValueMap<String, String> result = new LinkedMultiValueMap();
            
            // ...

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

5、META-INF/spring.factories

下面看一下 META-INF/spring.factories 里的 EnableAutoConfiguration 对应的配置类

在这里插入图片描述

我们在里面挑一个常用的 DataSourceAutoConfiguration类看一下

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(type = {"io.r2dbc.spi.ConnectionFactory"})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({
    DataSourcePoolMetadataProvidersConfiguration.class, 
    DataSourceInitializationConfiguration.class})
public class DataSourceAutoConfiguration {

}
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    // ...
}

通过 @ConfigurationProperties + @EnableConfigurationProperties 自动读取配置文件中的配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: .....
    username: root
    password: root

6、相关注解

1)条件注解

@Conditional 是 Spring 框架中的一个元注解,根据注解的条件来决定是否应该应用某个配置类或组件。

Spring 还提供了许多子注解,用于更精细地定义条件。

在这里插入图片描述

常用注解描述
@ConditionalOnBean容器中存在指定的 Bean 时,配置才会生效。
@ConditionalOnMissingBean容器中不存在指定的 Bean 时,配置才会生效。
@ConditionalOnClass当指定的类存在时,配置才会生效。
@ConditionalOnMissingClass当指定的类不存在时,配置才会生效。
@ConditionalOnWebApplication只有在web环境下,配置才会生效。
@ConditionalOnNotWebApplication只有在非web环境下,配置才会生效。
@ConditionalOnJava系统的Java版本符合需求,配置才会生效。
@ConditionalOnExpression满足指定的SpEL表达式,配置才会生效。
@ConditionalOnProperty指定的属性有指定的值,配置才会生效。
@ConditionalOnResource类路径下存在指定资源文件,配置才会生效。
@ConditionalOnSingleCandidate容器中只有一个指定的Bean,或Bean是首选Bean

2)顺序注解

注解描述
@AutoConfigureAfter在指定配置类加载之后加载
@AutoConfigureBefore在指定配置类加载之前加载
@AutoConfigureOrder指定加载配置的优先级,默认0

二、AutoConfigurationImportSelector 的处理

根据第一章的讲解,我们知道自动装配的核心在于 @Import 引入了 AutoConfigurationImportSelector

那么 AutoConfigurationImportSelector 中的逻辑又是在什么时候执行的呢?

1、DeferredImportSelector 的处理

ConfigurationClassPostProcessor 这个后置处理器的执行过程中,有一个 parse 环节

// org.springframework.context.annotation.ConfigurationClassParser

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    // parse...

    // 处理 DeferredImportSelector(SpringBoot自动装配就在这里处理)
    this.deferredImportSelectorHandler.process();
}

可以看到,parse 的最后会处理 DeferredImportSelector,而 AutoConfigurationImportSelector 实现了 DeferredImportSelector,因此也会在这里进行处理。

这里我们直接说自动装配相关的部分,相关的细节感兴趣的可以看一下 Spring源码分析(@Configuration)这篇文章,

2、DeferredImportSelectorHandler

跟进看一下 DeferredImportSelectorHandler 中的处理

// org.springframework.context.annotation.ConfigurationClassParser

// DeferredImportSelectorHandler 是 ConfigurationClassParser 的一个内部类
private class DeferredImportSelectorHandler {

    // 在 parse 处理 @Import 的时候调用,参数 importSelector 就是 AutoConfigurationImportSelector
    public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
        // 这里将 AutoConfigurationImportSelector 封装到 holder 中
        DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
        if (this.deferredImportSelectors == null) {
            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
            handler.register(holder);
            handler.processGroupImports();
        }
        else {
            // 添加到 deferredImportSelectors 集合,在 process 中处理
            this.deferredImportSelectors.add(holder);
        }
    }

    // 在 parse 方法的最后调用,处理 DeferredImportSelector
    public void process() {
        // 延迟处理的 ImportSelector 集合
        List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
        this.deferredImportSelectors = null;
        try {
            if (deferredImports != null) {
                // 委托给 DeferredImportSelectorGroupingHandler 进行处理
                DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
                // 排序
                deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
                // 注册
                deferredImports.forEach(handler::register);
                // 处理
                handler.processGroupImports();
            }
        }
        finally {
            this.deferredImportSelectors = new ArrayList<>();
        }
    }
}

3、DeferredImportSelectorGroupingHandler

可以看到,最终委托给 DeferredImportSelectorGroupingHandler 处理,我们重点关注 注册处理 这两块。

1)register

// org.springframework.context.annotation.ConfigurationClassParser

private class DeferredImportSelectorGroupingHandler {

    // key:AutoConfigurationGroup.class    value:DeferredImportSelectorGrouping
    private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
    private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();

    public void register(DeferredImportSelectorHolder deferredImport) {
        // deferredImport.getImportSelector() 就是 AutoConfigurationImportSelector
        // group 就是 AutoConfigurationImportSelector的内部类 AutoConfigurationGroup.class
        Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
        // 将 deferredImport 添加到 groupings 的 value 中
        DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
            (group != null ? group : deferredImport),
            // createGroup 构建 Group实例
            key -> new DeferredImportSelectorGrouping(createGroup(group)));
        // 添加 deferredImport,其中封装了 AutoConfigurationImportSelector
        grouping.add(deferredImport);
        this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
                                      deferredImport.getConfigurationClass());
    }
}

在这里插入图片描述

2)processGroupImports

// org.springframework.context.annotation.ConfigurationClassParser

private class DeferredImportSelectorGroupingHandler {

    public void processGroupImports() {
        for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
            Predicate<String> exclusionFilter = grouping.getCandidateFilter();
            // 这里 grouping.getImports() 返回的就是封装了所有 自动配置类 的Entry集合
            grouping.getImports().forEach(entry -> {
                // META-INF/spring.factories 中的自动配置类就会在这里进行处理
                ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
                try {
                    // 最后还是会调到 processImports --> 然后按 @Configuration 处理 --> processConfigurationClass
                    processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
                                   Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
                                   exclusionFilter, false);
                } 
                // ...
            });
        }
    }
}

grouping.getImports() 返回了所有 META-INF/spring.factories 中的自动配置类,下面看一下是怎么实现的。

// org.springframework.context.annotation.ConfigurationClassParser

private static class DeferredImportSelectorGrouping {
    public Iterable<Group.Entry> getImports() {
        for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                               deferredImport.getImportSelector());
        }
        return this.group.selectImports();
    }
}

打个断点看一下

在这里插入图片描述

this.group 其实就是 AutoConfigurationImportSelector 的内部类 AutoConfigurationGroup

4、AutoConfigurationGroup

下面我们看一下 AutoConfigurationGroup 中的相关处理

1)process

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup

@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 autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
        .getAutoConfigurationEntry(annotationMetadata);
    this.autoConfigurationEntries.add(autoConfigurationEntry);
    // 遍历 所有自动配置类 的 className
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}

下面看一下 getAutoConfigurationEntry 是怎么实现的

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 获取所有候选的配置类
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去重
    configurations = removeDuplicates(configurations);
    // 排除的 configurations
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = getConfigurationClassFilter().filter(configurations);
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 返回封装了 META-INF/spring.factories 中的自动配置类的Entry
    return new AutoConfigurationEntry(configurations, exclusions);
}

到这里是不是似曾相识。没错,后面就是第一章讲的读取 META-INF/spring.factories 的自动配置类了,这里不再赘述。

2)selectImports

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup

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

    // 排序并返回
    return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
        .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
        .collect(Collectors.toList());
}

三、自动装配(相关实现)

1、自动装配 - SpringAOP

为什么不加 @EnableAspectJAutoProxy,切面也能生效? ------> 因为SpringBoot自动装配已经帮我们实现了

在 SpringBoot官网 中可以看到如下解释:

在这里插入图片描述

  • 默认情况,SpringBoot自动装配的AOP使用的是CGLib动态代理
    • 在配置文件中配置 spring.aop.proxy-target-class=false 可以使用JDK动态代理
  • SpringBoot自动装配已经开启了AOP,因此 @EnableAspectJAutoProxy 不是必须的。

下面我们看一下SpringBoot中AOP的自动装配

在这里插入图片描述

@Configuration(proxyBeanMethods = false)
// 配置 spring.aop.auto = true 或 没有配置 spring.aop.auto,都会启用aop自动装配
// 配置 spring.aop.auto = false,自动装配就不会生效了,需要手动加 @EnableAspectJAutoProxy
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Advice.class)
    static class AspectJAutoProxyingConfiguration {

        @Configuration(proxyBeanMethods = false)
        // proxyTargetClass = false 表示使用jdk动态代理
        @EnableAspectJAutoProxy(proxyTargetClass = false)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                               matchIfMissing = false)
        static class JdkDynamicAutoProxyConfiguration {

        }

        @Configuration(proxyBeanMethods = false)
        // proxyTargetClass = true 表示使用cglib动态代理
        // springboot2.0+默认从jdk改为了cglib,也就是默认都为true。
        @EnableAspectJAutoProxy(proxyTargetClass = true)
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                               matchIfMissing = true)
        static class CglibAutoProxyConfiguration {

        }

    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                           matchIfMissing = true)
    static class ClassProxyingConfiguration {

        ClassProxyingConfiguration(BeanFactory beanFactory) {
            if (beanFactory instanceof BeanDefinitionRegistry) {
                BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
        }

    }

}

2、自动装配 - Spring事务

在这里插入图片描述

@Configuration(proxyBeanMethods = false)
// PlatformTransactionManager 加载的情况下,才会生效
@ConditionalOnClass(PlatformTransactionManager.class)
// 在这些类后边加载
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
		DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

    // 声明式事物的模板
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
	public static class TransactionTemplateConfiguration {
		@Bean
		@ConditionalOnMissingBean(TransactionOperations.class)
		public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
			return new TransactionTemplate(transactionManager);
		}
	}

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

		@Configuration(proxyBeanMethods = false)
        // 开启事务(proxyTargetClass = false 表示使用jdk动态代理)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
        // 开启事务(proxyTargetClass = true 表示使用cglib动态代理)
        // springboot2.0+默认从jdk改为了cglib,也就是默认都为true。
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}
}

3、自动装配 - SpringMVC

在这里插入图片描述

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
// 在 DispatcherServletAutoConfiguration 配置类之后配置
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
    // 引入 EnableWebMvcConfiguration
	@Import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {...}
    
    /**
	 * 配置相当于 @EnableWebMvc
	 */
    @Configuration(proxyBeanMethods = false)
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration 
        implements ResourceLoaderAware {...}
}
@AutoConfigureOrder(Integer.MIN_VALUE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({DispatcherServlet.class})
// 在 ServletWebServerFactoryAutoConfiguration 配置类之后配置
@AutoConfigureAfter({ServletWebServerFactoryAutoConfiguration.class})
public class DispatcherServletAutoConfiguration {
    
    @Configuration(proxyBeanMethods = false)
    @Conditional({DefaultDispatcherServletCondition.class})
    @ConditionalOnClass({ServletRegistration.class})
    @EnableConfigurationProperties({WebMvcProperties.class})
    protected static class DispatcherServletConfiguration {
        protected DispatcherServletConfiguration() {}

        // 前端控制器 DispatcherServlet
        @Bean(name = {"dispatcherServlet"})
        public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            // ...
            return dispatcherServlet;
        }

        // 文件上传相关bean
        @Bean
        @ConditionalOnBean({MultipartResolver.class})
        @ConditionalOnMissingBean(name = {"multipartResolver"})
        public MultipartResolver multipartResolver(MultipartResolver resolver) {
            return resolver;
        }
    }
}
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Integer.MIN_VALUE)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties({ServerProperties.class})
@Import({
    BeanPostProcessorsRegistrar.class, 
    ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,	// 内置Tomcat
    ServletWebServerFactoryConfiguration.EmbeddedJetty.class, 
    ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {...}

四、自定义 starter

看完自动装配的源码,我们可以尝试自定义 starter,来实现自动装配。

1、pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <!-- 定义starter的坐标 -->
    <groupId>jwt-utils</groupId>
    <artifactId>jwt-spring-boot-starter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    
    <name>jwt-spring-boot-starter</name>
    
</project>

2、Properties实体类

@Data
@ConfigurationProperties(prefix = "auth")
public class ClientProperties {
    /**
     * 客户端名称
     */
    private String clientId;
    /**
     * 客户端秘钥
     */
    private String secret;
    /**
     * 拦截器拦截路径
     */
    private List<String> includeFilterPaths;
    /**
     * 拦截器放行路径
     */
    private List<String> excludeFilterPaths;
}

3、Config配置类

@Slf4j
@Configuration
// 只有配置了 auth.clientId 和 auth.secret 属性,当前配置才会生效。
@ConditionalOnProperty(prefix = "auth", name = {"clientId", "secret"})
@EnableConfigurationProperties(ClientProperties.class)
public class AuthAutoConfiguration {
    // 实现一些starter的逻辑....
}

4、spring.factories

resources/META-INF/spring.factories 目录下编写

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.auth.config.AuthAutoConfiguration

5、使用自动装配

在要使用的模块的pom文件中添加starter依赖

<dependency>
    <groupId>jwt-utils</groupId>
    <artifactId>jwt-spring-boot-starter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

application.yaml文件添加配置

auth:
  clientId: user-service
  secret: 1234
  includeFilterPaths:
  - /path1
  - /path2
;