容器希望中间件只提供相关的connector
依赖给业务方使用,而不是具体的实现。通过connector
带来的好处就是,中间件升级jar
包,不会影响业务方的使用,业务方对其无感知。并且业务代码里也不会引入多于的jar
包,导致不必要的jar
冲突。
Java 6 has introduced a feature for discovering and loading implementations matching a given interface: Service Provider Interface (SPI).
SPI
能够将接口和实现类解耦,给业务方相关的接口类,接口的实现类在放在某个classpath
下,通过SPI
来做到接口匹配对应的实现类。
基于自定义ClassLoader
和SPI
来做到上图的内容
//定义接口模块
public interface Person {
void greet(String name);
}
//定义接口实现模块
public class YoungPerson implements Person {
public void greet(final String name) {
System.out.println("hello old person");
}
}
public class OldPerson implements Person {
public void greet(final String name) {
System.out.println("hello young person");
}
}
//在META-INF/services下添加com.laomei.test.Person
com.laomei.spi.test.OldPerson
com.laomei.spi.test.YoungPerson
//测试模块,测试模块只依赖接口模块,不依赖实现模块
public class Main {
public static void main(String[] args) throws MalformedURLException {
URLClassLoader customClassLoader = customClassLoader();
Thread.currentThread().setContextClassLoader(customClassLoader);
ServiceLoader<Person> person = ServiceLoader.load(Person.class);
Iterator<Person> iterator = person.iterator();
while (iterator.hasNext()) {
Person customPerson = iterator.next();
customPerson.greet(" user");
}
}
public static URLClassLoader customClassLoader() throws MalformedURLException {
String path = "jar:file:///opt/spi-test-implement.jar!/";
return new URLClassLoader(new URL[]{ new URL(path) });
}
}
//结果
hello young person
hello old person