ServiceLoader机制及实例
所属分类 java
浏览量 1358
ServiceLoader机制及实例
动态加载某个接口的实现类
全局扫描所有的Class,判断是否实现了该接口,效率低
JDK提供了 ServiceLoader 机制
SPI Service Provider Interface
服务提供发现机制
有不少框架用它来做服务的扩展发现 动态替换发现机制
jar包 META-INF/services/ 目录下建立一个文件
文件名 接口的全限定名,文件内容可以有多行,每行是该接口实现类的全限定名
典型使用场景 slf4j 日志桥接
jcl-over-slf4j-1.7.22.jar
/META-INF/services/org.apache.commons.logging.LogFactory
org.apache.commons.logging.impl.SLF4JLogFactory
log4j-to-slf4j-2.10.0.jar
/META-INF/services/org.apache.logging.log4j.spi.Provider
org.apache.logging.slf4j.SLF4JProvider
实例
4个工程
intf 接口 dyyx.Pet
impl 实现1 dyyx.Cat
impl2 实现2 dyyx.Dog
test ServiceLoader 测试
/service-load-impl/src/main/resources/META-INF/services/dyyx.Pet
dyyx.Cat
/service-load-impl2/src/main/resources/META-INF/services/dyyx.Pet
dyyx.Dog
测试代码 Hello.java
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;
public class Hello {
private static final String DIR = "/Users/dugang/fun/hellocode/demo/serviceload/";
public static void main(String[] args) throws Exception {
System.out.println("hello");
URL url1 = getUrl("impl");
URL url2 = getUrl("impl2");
System.out.println(url1);
System.out.println(url2);
// 自定义类加载器
ClassLoader classLoader = new URLClassLoader(new URL[]{url1,url2});
System.out.println(classLoader);
Pet cat = (Pet) classLoader.loadClass("dyyx.Cat").newInstance();
cat.sayHello();
// 不能在 classpath里加入实现jar包 或 实现工程impl,否则 classload 为 AppClassLoader
System.out.println(cat.getClass().getClassLoader());
System.out.println();
ClassLoader cl = null;
// 加载不到
showServices(cl);
// 加载不到
cl = Pet.class.getClassLoader();
showServices(cl);
// 可以加载到
cl = classLoader;
showServices(cl);
}
private static void showServices(ClassLoader cl){
System.out.println("ClassLoader="+cl);
if(cl!=null){
System.out.println(cl.getClass().toString());
}
// ClassLoader loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl
ServiceLoader services = ServiceLoader.load(Pet.class, cl);
int num = 0;
Iterator it = services.iterator();
while (it.hasNext()) {
num++;
Pet pet = it.next();
pet.sayHello();
}
System.out.println("services.num="+num);
System.out.println("\n\n");
}
private static URL getUrl(String type)throws Exception{
String str = "file:%s%s/target/service-load-%s-1.0.jar";
str = String.format(str, DIR,type,type);
return new URL(str);
}
}
file:/Users/dugang/fun/hellocode/demo/serviceload/impl/target/service-load-impl-1.0.jar
file:/Users/dugang/fun/hellocode/demo/serviceload/impl2/target/service-load-impl2-1.0.jar
java.net.URLClassLoader@7f31245a
Cat sayHello Thu Jun 12 12:55:45 CST 2019
java.net.URLClassLoader@7f31245a
ClassLoader=null
services.num=0
ClassLoader=sun.misc.Launcher$AppClassLoader@2a139a55
class sun.misc.Launcher$AppClassLoader
services.num=0
ClassLoader=java.net.URLClassLoader@7f31245a
class java.net.URLClassLoader
Cat sayHello Wed Jun 12 22:55:45 CST 2019
Dog sayHello Wed Jun 12 22:55:45 CST 2019
services.num=2
完整代码
https://gitee.com/dyyx/hellocode/tree/master/demo/serviceload
jar tvf service-load-impl-1.0.jar
上一篇
下一篇
logback的内部日志输出
System.out重定向到slf4j
各种日志重定向到slf4j
什么是smart beta
java初始化顺序
springboot2启动过程简单分析