SPI

SpringBoot的自动装配是通过SPI的方式实现的,并进行了进一步的优化,从而实现了自动装配。SPI全称为Serveice Provider Interface,是Java提供的一种服务发现机制。它允许不同的组件在运行时动态的扩展、替换和加载实现SPI是一种基于接口和实现分离的设计模式。 在SPI机制中,定义一个接口作为服务的标准化接口,然后通过类路径下提供特定配置文件来指定具体的实现。这个配置文件通常位于META-INF/services目录下,以接口的全限定名命名。配置文件中列出了实现该接口的具体类的全限定名。 当需要使用某项服务时,应用程序可以通过SPI机制查找平加载对应的实现类。Java运行时会通过读取配置文件获取到实现类的信息,并实例化对应的类。这样能够做到在不修改代码的情况下,通过添加/替换配置文件中的实现类,来改变程序的行为或者增加新功能。

SPI的应用

  1. JDBC数据库驱动
  2. 日志框架(SLF4)

SpringBoot自动装配原理

SpringBoot自动配置是默认开启的,spring.boot.enableautoconfiguration=true,可以通过application.propertiesapplication.yml来关闭自动配置。 SpringBoot应用都会创建一个启动类,启动类上包含了@SpringBootApplication注解,这个注解是一个复合的注解,分别对这三个注解进行了封装@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan

1
2
3
4
5
6
7
8
@SpringBootApplication  
public class DemoApplication {  
  
    public static void main(String[] args) {  
        SpringApplication.run(DemoApplication.class, args);  
    }  
  
}

@SpringBootApplication注解的实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Inherited  
@SpringBootConfiguration  
@EnableAutoConfiguration  
@ComponentScan(  
    excludeFilters = {@Filter(  
    type = FilterType.CUSTOM,  
    classes = {TypeExcludeFilter.class}  
), @Filter(  
    type = FilterType.CUSTOM,  
    classes = {AutoConfigurationExcludeFilter.class}  
)}  
)  
public @interface SpringBootApplication

@SpringBootConfiguration:用于标识一个类是SpringBoot的配置类。 @EnableAutoConfiguration:启动SpringBoot的自动配置机制。 @ComponentScan:扫描被@Component注解的Bean,注解默认会扫描启动类所在的包下的所有类。

@EnableAutoConfiguration是实现SpringBoot自动配置的核心,该注解上通过@Import注解导入了一个AutoConfigurationImportSelector类,AutoConfigurationImportSelector 类实现了 ImportSelector接口,也就实现了这个接口中的 selectImports方法,这个方法主要是用来获取所有符合条件的类的全限定类名。 @EnableAutoConfiguration源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@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源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class AutoConfigurationImportSelector implements DeferredImportSelector{  
  
    public String[] selectImports(AnnotationMetadata annotationMetadata) {  
        if (!this.isEnabled(annotationMetadata)) {  
            return NO_IMPORTS;  
        } else {  
            AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);  
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());  
        }  
    }
}    

通过selectImports()方法调用getAutoConfigurationEntry(annotationMetadata)getAutoConfigurationEntry(annotationMetadata)方法通过SpringFactoriesLoader.loadFactoryNames(),扫描所有含有META-INF/spring.factoriesjar包,然后读取META-INF/spring.factories文件中所配置的类的全限定类名。在这些配置类中所定义的Bean会根据条件注解来决定是否需要将其导入到Spring的容器中。 一般条件判断都会有@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,并将这个配置类所有的Bean放入Spring容器中。