首页   快速返回

ServiceLoader机制及实例     所属分类 java
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启动过程简单分析