https://blog.csdn.net/yangcheng33/article/details/52631940
https://segmentfault.com/a/1190000017517197?utm_source=tag-newest
Java SPI的具体约定为:当服务的提供者提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); }
也就是说把自己加载不了的类加载到TCCL中(通过Thread.currentThread()获取,简直作弊啊!
ContextClassLoader默认存放了AppClassLoader的引用,由于它是在运行时被放在了线程中,所以不管当前程序处于何处(BootstrapClassLoader或是ExtClassLoader等),在任何需要的时候都可以用Thread.currentThread().getContextClassLoader()取出应用程序类加载器来完成需要的操作。
getConnection
由于TCCL本质就是当前应用类加载器,所以之前的初始化就是加载在当前的类加载器中,这一步就是校验存放的driver是否属于调用者的Classloader
tomcat与spring使用这种技术
归纳:
启动类加载器 interface A
系统类加载器 B implement A
A a = (A)当前线程类加载器.loadclass(B).newInstance
List<A>.add(a);
List.get(x).run();