01|自定义Starter
1.1 引入依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>white.colde</groupId>
<artifactId>spring-starter</artifactId>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
1.2 创建业务类
public interface LogService {
void log(String log);
}
public class LogServiceImpl implements LogService {
@Override
public void log(String log) {
System.out.println("log:"+log);
}
}
1.3 创建配置类
@Configuration
public class LogServiceAutoConfiguration {
@Bean
public LogService getLogService(){
return new LogServiceImpl();
}
}
1.4 创建配置文件
在resources目录下创建META-INF文件夹,并创建spring.factories文件,用于声明配置类完整路径
org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxx.LogServiceAutoConfiguration
1.5 使用
在所需项目中引入starter依赖,即可使用starter中所定义的bean对象
02|starter自动化配置原理
依据自定义starter的流程,可以大致猜测Spring自定义Starter的思路应该如下:
- 1、扫描导入所有包中的spring.factories文件
- 2、解析出配置文件中的Spring配置类
- 3、解析配置类,注入配置类中定义的所有Spring Bean并加入到IoC容器中
在1的starter的示例中,最终在spring.factories中声明了一对属性配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxx.LogServiceAutoConfiguration
打开EnableAutoConfiguration的源码可以发现,EnableAutoConfiguration是一个注解,并在EnableAutoConfiguration注解之上导入了AutoConfigurationImportSelector类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
查看AutoConfigurationImportSelector类,从方法名就可以看出selectImports方法应该就是我们所找的方法,跟踪方法,最终会调用getCandidateConfigurations方法,并在方法中调用了SpringFactoriesLoader.loadFactoryNames方法载入了所有jar包中的的spring.factories中的配置类信息
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
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;
}
}
最终会将解析出的配置信息注册到beanFactory中,等待IoC容器进行实例化