01|自定义Starter

1.1 引入依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>white.colde</groupId>
  7. <artifactId>spring-starter</artifactId>
  8. <version>0.0.1</version>
  9. <dependencies>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-autoconfigure</artifactId>
  13. </dependency>
  14. </dependencies>
  15. <dependencyManagement>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-dependencies</artifactId>
  20. <version>2.4.1</version>
  21. <type>pom</type>
  22. <scope>import</scope>
  23. </dependency>
  24. </dependencies>
  25. </dependencyManagement>
  26. </project>

1.2 创建业务类

  1. public interface LogService {
  2. void log(String log);
  3. }
  4. public class LogServiceImpl implements LogService {
  5. @Override
  6. public void log(String log) {
  7. System.out.println("log:"+log);
  8. }
  9. }

1.3 创建配置类

  1. @Configuration
  2. public class LogServiceAutoConfiguration {
  3. @Bean
  4. public LogService getLogService(){
  5. return new LogServiceImpl();
  6. }
  7. }

1.4 创建配置文件

在resources目录下创建META-INF文件夹,并创建spring.factories文件,用于声明配置类完整路径

  1. 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中声明了一对属性配置

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxx.LogServiceAutoConfiguration

打开EnableAutoConfiguration的源码可以发现,EnableAutoConfiguration是一个注解,并在EnableAutoConfiguration注解之上导入了AutoConfigurationImportSelector类

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)
  7. public @interface EnableAutoConfiguration {
  8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  9. Class<?>[] exclude() default {};
  10. String[] excludeName() default {};
  11. }

查看AutoConfigurationImportSelector类,从方法名就可以看出selectImports方法应该就是我们所找的方法,跟踪方法,最终会调用getCandidateConfigurations方法,并在方法中调用了SpringFactoriesLoader.loadFactoryNames方法载入了所有jar包中的的spring.factories中的配置类信息

  1. public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
  2. ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
  3. @Override
  4. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  5. if (!isEnabled(annotationMetadata)) {
  6. return NO_IMPORTS;
  7. }
  8. AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
  9. return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  10. }
  11. protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
  12. if (!isEnabled(annotationMetadata)) {
  13. return EMPTY_ENTRY;
  14. }
  15. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  16. List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
  17. configurations = removeDuplicates(configurations);
  18. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  19. checkExcludedClasses(configurations, exclusions);
  20. configurations.removeAll(exclusions);
  21. configurations = getConfigurationClassFilter().filter(configurations);
  22. fireAutoConfigurationImportEvents(configurations, exclusions);
  23. return new AutoConfigurationEntry(configurations, exclusions);
  24. }
  25. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  26. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
  27. getBeanClassLoader());
  28. Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
  29. + "are using a custom packaging, make sure that file is correct.");
  30. return configurations;
  31. }
  32. }

最终会将解析出的配置信息注册到beanFactory中,等待IoC容器进行实例化