致敬大师,致敬未来的你
生命不止,学习不息,运动不息
Life does not stop, learning does not stop, movement does not stop
总述
SPI机制,全名 Service Provider Interface
希望看完这篇文章之后,再看java的SPI机制就可以一路通畅了
学过反射的同学都知道,java有一种类的加载机制,比如说有一个com.bean.Person类,要获取它的Class对象,可以通过以下代码获取
Class<Person> clzz = Class.forname("com.bean.Person");
SPI机制
只要知道以上的反射,就不难理解SPI机制了
SIP机制其实分为以下两个步骤:
没错,你没看错,就是这么简单,但是,为什么要搞这么复杂呢,直接Class.forname加载不就行了么,接下来就解答:
在各种中间件中,有很多需要扩展的点,比如netty、spring boot、dubbo
但是中间件不知道你扩展的全类名叫什么,这就是一种扩展机制
但是,又说,spring中的注解方式不也是一种方式么,对的,这两种方式都行,还有XML方式、等等,主要是看中间件喜欢那种方式
解析文件
以下是中间件中常用的获取项目下文件的方法,也是mybatis、spring、等等中间件常用的
filePath为项目的相对目录
URL resource = Thread.currentThread().getContextClassLoader().getResource(filePath);
生成对象
Class<?> clz = Class.forName(className);
Object obj = clz.newInstance();
总结
这么简单?
对,你没看错,就是这么简单
SPI机制就是 解析文件 + 生成对象
那么上面两步合下来就是下边:
编写自己的SPI机制
Person接口
package com.spi;
public interface Person {
public String getName();
}
YeollowPerson实现类
package com.spi;
public class YeollowPerson implements Person{
@Override
public String getName() {
return "yeollow";
}
}
resource/com.spi.person文件
yeollow=com.spi.YeollowPerson
black=com.spi.BlackPerson
white=com.spi.WhitePerson
mian 方法
package com.spi;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class SPITest {
static Map<String,Class<?>> map = new HashMap<String,Class<?>>();
public static void main(String[] args) throws Exception {
String fileName = "com.spi.person";
scanFile(fileName);
YeollowPerson bean = (YeollowPerson)getBean("yeollow");
System.out.println(bean.getName());
}
//根据文件名扫描文件
static void scanFile(String fileName) throws Exception {
URL resource = Thread.currentThread()
.getContextClassLoader()
.getResource("resource/" + fileName);
BufferedInputStream bis = (BufferedInputStream) resource.getContent();
BufferedReader br = new BufferedReader(new InputStreamReader(bis));
String str = "";
while((str=br.readLine()) != null) {
String[] split = str.split("=");
String name = split[0];
Class<?> clz = Class.forName(split[1]);
map.put(name, clz);
}
}
//获取bean
static Object getBean(String beanName) throws Exception {
Class<?> clz = map.get(beanName);
return clz.newInstance();
}
}
上面就实现了一个自己定制的SPI机制,解析的文件可以以任意形式,可以不实现接口 ,文件中直接写类名、种种看自己心情即可
如果比较重要的场景,还是定制一个固定的规范比较好
但是上面是否叫SPI机制,就不知道了,你可以自己命名