ServiceLoader内部实现分析

时间:2022-12-22 17:23:50

ServiceLoader内部实现分析

背景

对于技术,要知其然更要知其所以然,在上一篇文章简单介绍了ServiceLoader的基本使用,完成了知其然的阶段,本篇要完成知其所以然。完成对其基本实现原理的分析。

原理分析

ServiceLoader类是final类型,并且实现了Iterable接口,使得该类可以被迭代,不能被继承。

ServiceLoader内部实现分析

接口load(Class<S> service)和load(Class<S> service,ClassLoader loader)都会直接new一个新的ServiceLoader类,在实例化时会调reload方法实例化LazyIterator迭代类。

ServiceLoader内部实现分析

在该接口调用返回后并去查找并加载指定接口的实现类,这是完成查找前的配置工作。接口实现类的查找是在ServiceLoader迭代时通过调用next和hasNext方法去完成。接下来分析ServiceLoader的迭代过程。对ServiceLoader进行Iterator迭代,在调用hasNext时,会调用lookupIterator的hasNext,并调用hasNextService方法,而该方法是查找实现类全限定名的关键位置

ServiceLoader内部实现分析

这就是为什么要在META-INF下创建要查询接口全限定名命名的文件了。

在这步判断之后,ServiceLoader内部就已经有了接口对应的实现类的全限定名集合,在接下来调用next接口中会调用nextService方法。而该方法内部会调用Class.forName和clazz.newInstance()获取到接口实现类的实例。

nextService实现如下:

ServiceLoader内部实现分析

ServiceLoader缺点分析

虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。

获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类

总结

如上所述完成后就分析完了ServiceLoader对接口实现类的查询,其实可以发现核心实现也没有什么难的地方,无非就一下几点:

  • 通过资源文件指定实现了接口的实现类名称;

  • 使用java I/O方式查找该资源文件获取到该文件的信息及其内容;

  • 将资源文件内部的各个实现类的名称存储在缓存*接下来使用;

  • 使用Class.forName通过类名构造类并对其实例化返回给调用方,即可供调用方使用了。

ServiceLoader内部实现分析