META-INF下文件的详解以及java的spi机制

上图所示的三个文件,1涉及到spi机制,2与3均是自动装配的配置文件。 以下具体说明

services.xxx.xxx(Java SPI 机制)

SPI的全称是Service Provider Interface,中文名为服务提供者接口,是一种服务发现机制,基于JDK内置的动态加载实现扩展点的机制(通过在 ClassPath 路径下的 META-INF/services 文件夹查找文件,自动加载文件里所定义的类),使得框架扩展和替换组件变得容易。

  • 当服务提供者提供了接口的一种具体实现后,在jar包的META-INF/services目录下创建一个以“接口全路径名”为命名的文件,内容为实现类的全路径名
  • 当外部程序装配这个 jar 包时,就能通过该 jar 包 META-INF/services/ 目录中的配置文件找到具体的实现类名,并装载实例化,从而完成模块的注入

优点: 定制化实现接口解耦

缺点: 通过观察ServiceLoader,可以发现并没有额外的加锁机制,所以会存在并发问题获取对应的实现类不够灵活,从上面例子可以看出,需要使用迭代器的方式获取需要知道接口的所有具体实现类,所以每次都要加载和实例化所有的实现类

这里拿芋道源码举个例子: 芋道自定义了基于 Redis 实现验证码的存储,扩展了源CaptchaCacheService功能,并且配置完成模块注入

spring.factories

我们都知道在spring boot项目中,只要用注解@Configuration、@Bean、@Compont等注解标注的类spring boot会自动为他们创建bean。同时被注解编注的类创建bean有一个前提,只对启动类所在的basepackage下的所有带有@Component等注解的类才会创建bean。(@ComponentScan默认只扫描同包、子包下的所有类)。

spring boot 默认的包扫描范围=而在项目根目录以外的Bean,也就是导入的spring-boot-starter-xxx 的maven依赖 是根据 /META-INF/spring.factories下的文件去进行加载的

注解
  • @SpringBootApplication :这是springboot最核心的注解,当然也是组合注解
  • @EnableAutoConfiguration 是自动装配的总开关。我们将以该注解入手,增强对自动配置的理解。
  • @Import(AutoConfigurationImportSelector.class) 导入自动配置的ImportSelectot类。
核心类及方法:
  • AutoConfigurationImportSelector 导入需要自动装配的类或Bean。
  • getCandidateConfigurations 获取所有组件的配置类。
  • AutoConfigurationMetadataLoader.loadMetadata 加载所有自动装配组件配置类的条件(@Conditional 过滤条件)。
  • filter.match(candidates, this.autoConfigurationMetadata) 对各组件中全部配置类根据@Conditional进行条件过滤。
@SpringBootApplication注解
@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 {
}
#在自动装配链中的AutoConfigurationImportSelector.getCandidateConfigurations()方法中SpringFactoriesLoader.loadFactoryNames方法
	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;
	}

SpringFactoriesLoader 类似上文提到的SPI 机制,是以服务接口命名的文件是放在 META-INF/spring.factories 文件夹下,定义了一个key为EnableAutoConfiguration,SpringFactoriesLoader 会查找所有 META-INF/spring.factories 文件夹中的配置文件,并把 Key 为 EnableAutoConfiguration 所对应的配置项通过反射实例化为配置类并加载到容器中,SpringBoot默认情况下给我们提供了100多个AutoConfiguration的类

spring.xxx.imports

org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件功能与 spring.factories一样。都是用来加载自动装配的类。

从spring boot2.7开始,慢慢不支持META-INF/spring.factories文件了需要导入的自动配置类可以放在/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中