ServiceLoader类加载原理

前言

ServiceLoader是实现SPI一个重要的类。是Mark Reinhold在java1.6引入的类,为了解决接口与实现分离的场景。在资源目录META-INF/services中放置提供者配置文件,文件名以接口的类名命名,里面的内容为需要加载的实现类。然后在app运行时,遇到Serviceloader.load(XxxInterface.class)时,会到META-INF/services的配置文件中寻找这个接口对应的实现类全路径名,然后使用Class.forName()(传入设定的类加载器)完成类的加载。

下面分别以JDBC的例子来讲解SPI。

ServiceLoader:

ServiceLoader类加载原理_第1张图片

在mysql-connector包中已经满足了spi的配置,现在看看DriverManager是如何使用ServiceLoader实现mysql Driver的加载的。

DriverManager(jdk1.8.0_151)中有如下的静态代码块:

ServiceLoader类加载原理_第2张图片

查看loadInitialDrivers()方法,核心代码如下:

ServiceLoader类加载原理_第3张图片

ServiceLoader loadedDrivers = ServiceLoader.load(Driver.class);

这句代码中将线程上下文加载器作为后续加载实现类的加载器(Thread.currentThread().getContextClassLoader()),如果不设定的话就使用AppClassLoader作为类加载器。并实例化ServiceLoader 和内置的LazyIterator。

LazyIterator:实现懒加载机制,在调用到hasNextService()和nextService()方法时才去找相应目录下的类名,并加载相应的类。

while(driversIterator.hasNext()) {

driversIterator.next();

}


ServiceLoader类加载原理_第4张图片


ServiceLoader类加载原理_第5张图片

在加载com.mysql.jdbc.Driver的时候Driver类有如下静态代码块:


ServiceLoader类加载原理_第6张图片

可以知道,在加载Driver类的时候会new Driver()类并会注册到DriverManager中的CopyOnWriteArrayList中。private final static CopyOnWriteArrayListregisteredDrivers =new CopyOnWriteArrayList<>();

总结

在线程创建过程中可以设定private ClassLoader contextClassLoader属性,并在ServerLoader中使用该类加载器,使得父类加载器请求子类加载器去完成类加载的动作,打通了双亲委派模型的层次结构来逆向使用类加载器,打破java推荐的双亲委派模型。

你可能感兴趣的:(ServiceLoader类加载原理)