Spring中的spring.factories⽂件⽤法(Spring如何加载第三⽅Bean)
⽬录
Spring的spring.factories⽂件⽤法
问题
解决
SpringBoot的扩展机制之Spring Factories
什么是 SPI机制
Spring Boot中的SPI机制
Spring Factories实现原理是什么
Spring Factories在Spring Boot中的应⽤
Spring的spring.factories⽂件⽤法
在springBoot中,它⾃动扫描包的时候,只会扫描⾃⼰模块下的类。
问题
如果我们不想被Spring容器管理的Bean的路径下不再SpringBoot的包扫描路径下,怎么办呢?如何加载别的第三⽅Bean呢?
解决
⾸先我们创建⼀个⼯程,另外创建⼀个与启动类不在⼀个级别的⽬录。
第⼀种⽅法就是使⽤在启动类上加上@Import注解。
@Import(value = {Test.class})
第⼆种⽅法就是创建spring.factories⽂件
现在我们将其改造⼀下,采⽤spring.factories的⽅式去加载Test类,在resources⽬录下新建⼀个META-INF的⽬录,然后再新建⼀个spring.factories⽂件,⽂件内容为:
下⾯第⼆条就是我们⾃⼰的类的路径。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=/
com.fig.Test
然后在springBoot中的启动类中将@Import注释掉,启动⼀下,在控制台上就会发现,我们⾃⼰的配置类已经加载到Spring容器中去了,所以Spring可以加载⼀个⼯程下的任意⼀下⼯程类了。
应⽤
下⾯就是我在Nacos源码中看到的,可以看到spring.factories⽂件中内容,与我们⾃⼰类加载到Spring容器中是⼀样的道理。
SpringBoot的扩展机制之Spring Factories
写在前⾯:Spring Boot中有⼀种⾮常解耦的扩展机制:Spring Factories。这种扩展机制实际上是仿照Java中的SPI扩展机制来实现的。
什么是 SPI机制
SPI的全名为Service Provider Interface.⼤多数开发⼈员可能不熟悉,因为这个是针对⼚商或者插件的。在java.util.ServiceLoader的⽂档⾥有⽐较详细的介绍。
简单的总结下java SPI机制的思想。我们系统⾥抽象的各个模块,往往有很多不同的实现⽅案,⽐如⽇志模块的⽅案,xml解析模块、jdbc模块的⽅案等。⾯向的对象的设计⾥,我们⼀般推荐模块之间基于接⼝编程,模块之间不对实现类进⾏硬编码。⼀旦代码⾥涉及具体的实现类,就违反了可拔插的原则,如果需要替换⼀种实现,就需要修改代码。为了实现在模块装配的时候能不在程序⾥动态指明,这就需要⼀种服务发现机制。
java SPI就是提供这样的⼀个机制:为某个接⼝寻服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。
Spring Boot中的SPI机制
在Spring中也有⼀种类似与Java SPI的加载机制。它在META-INF/spring.factories⽂件中配置接⼝的实现类名称,然后在程序中读取这些配置⽂件并实例化。
这种⾃定义的SPI机制是Spring Boot Starter实现的基础。
Spring Factories实现原理是什么
spring-core包⾥定义了SpringFactoriesLoader类,这个类实现了检索META-INF/spring.factories⽂件,并获取指定接⼝的配置的功能。在这个类中定义了两个对外的⽅法:
loadFactories 根据接⼝类获取其实现类的实例,这个⽅法返回的是对象列表。
loadFactoryNames 根据接⼝获取其接⼝类的名称,这个⽅法返回的是类名的列表。
上⾯的两个⽅法的关键都是从指定的ClassLoader中获取spring.factories⽂件,并解析得到类名列表,具体代码如下↓
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = Name();
try {
Enumeration<URL> urls = (classLoader != null ? Resources(FACTORIES_RESOURCE_LOCATION) :
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = Element();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = Property(factoryClassName);
result.addAll(Arrays.asList(StringUtilsmaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + Name() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
spring ioc注解}
从代码中我们可以知道,在这个⽅法中会遍历整个ClassLoader中所有jar包下的spring.factories⽂件。也就是说我们可以在⾃⼰的jar中配置spring.factories⽂件,不会影响到其它地⽅的配置,也不会被别⼈的配置覆盖。
spring.factories的是通过Properties解析得到的,所以我们在写⽂件中的内容都是安装下⾯这种⽅式配置的:
如果⼀个接⼝希望配置多个实现类,可以使⽤','进⾏分割。
Spring Factories在Spring Boot中的应⽤
在Spring Boot的很多包中都能够到spring.factories⽂件,接下来我们以spring-boot包为例进⾏介绍
在⽇常⼯作中,我们可能需要实现⼀些SDK或者Spring Boot Starter给被⼈使⽤时,我们就可以使⽤Factories机制。Factories机制可以让SDK或者Starter的使⽤只需要很少或者不需要进⾏配置,只需要在服务中引⼊我们的jar包即可。
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。

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