SpringBoot的扩展机制(类SPI)
我们已经知道Java的SPI机制是⼀个良好的协同第三⽅扩展的⽅案,Spring Boot也借鉴了类似的⼿段。关于Java SPI机制原理可以点击这
⾥。当然这种机制并不是Spring Boot才有,Spring早期设计就已经考虑了这种功能
⼀、Spring的扩展机制
Spring约定,在jar包(classpath)下新建META-INF\spring.factories⽂件,⽂件内容为Properties格式,其中key可以是接⼝、注解、
或者抽象类的全类名。value为相应的实现全类名,当存在多个实现类时,⽤“,”进⾏分割。Spring在启动时,会去读取加载这些类。其中
负责读取的类是:
io.support.SpringFactoriesLoader
注意,这个类于Spring 3.2就有了,并不是Spring Boot时期出现的,但是在Spring Boot出现之前,⼏乎没有第三⽅组件使⽤这个机制,
只有Spring内部会使⽤,直到Spring Boot出现,为了实现第三⽅组件⾃动装配,这个类才被⼈所熟知,⾜以证明Spring设计的前瞻性,
官⽅解释是:
框架内部使⽤的通⽤⼯⼚加载机制。
SpringFactoriesLoader从“META-INF/spring.factories”⽂件中加载并实例化给定类型的⼯⼚,这些⽂件可能存在于类路径中的多个JAR⽂件中。spring.factories⽂件必example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
其中example.MyService是接⼝的名称,MyServiceImpl1和MyServiceImpl2是两个实现。
⾃:3.2
作者:
Arjen Poutsma、Juergen Hoeller、Sam Brannen
Spring把这个命名为⼯⼚,这是出于什么想法?
⼆、Spring内部使⽤
上⾯说到,Spring Boot出现之前,这个机制⼀直是Spring内部使⽤,我们来看看Spring内部是如何使⽤的:
org.springframework.boot.SpringApplication#SpringApplication(io.ResourceLoader,
java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
springboot框架的作用
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
这⾥我们只关注第6⾏:
org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[],
java.)
这⾥是调⽤了SpringFactoriesLoader去META-INF\spring.factories⾥配置的⽂件,并且限定了类型为:
t.ApplicationContextInitializer
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, args) {
ClassLoader classLoader = getClassLoader();
/
/ Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
这是个接⼝类型,我们可以了解下他的作⽤是什么:
官⽅的解释是:
⽤于在刷新之前初始化Spring ConfigurableApplicationContext的回调接⼝。
通常在需要对应⽤程序上下⽂进⾏编程初始化的web应⽤程序中使⽤。例如,针对上下⽂环境注册属
性源或激活配置⽂件。请参阅ContextLoader和FrameworkServlet 建议ApplicationContextInitializer处理器检测Spring的有序接⼝是否已实现,或者@Order注释是否存在,如果存在,则在调⽤之前对实例进⾏相应排序。
⾃:3.1
另请参见:
org.t.ContextLoader.customizeContext, org.t.ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARA 作者:克⾥斯梁
类型参数: –应⽤程序上下⽂类型
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
三、Spring Boot⾃动装配使⽤
我们直接检索谁调⽤了SpringFactoriesLoader的⽅法,发现
io.support.SpringFactoriesLoader#loadFactoryNames()的调⽤地⽅有三处(除去内部调⽤的地⽅):
io.support.SpringFactoriesLoader#loadFactories()的调⽤地⽅有2处(除去内部调⽤的地⽅):
都是⾃动装配调⽤的,到这我们⾄少可以确定Spring提供的扩展机制⽬前只被2中情况使⽤,⼀种是Spring内部启动初始化,⼀种是⾃动装
配扩展,⾄于Spring Boot的⾃动装配请参考这篇⽂章:
《》

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。