ServiceLoader类加载原理

前言

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

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

ServiceLoader:

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

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

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

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

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

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

while(driversIterator.hasNext()) {

driversIterator.next();

}



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


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

总结

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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容