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 {@Overridepublic void log(String log) {System.out.println("log:"+log);}}
1.3 创建配置类
@Configurationpublic class LogServiceAutoConfiguration {@Beanpublic 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 {@Overridepublic 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容器进行实例化
