文章目录
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