时间:2021-05-19
在java中根据一个子类获取其父类或接口信息非常方便,但是根据一个接口获取该接口的所有实现类却没那么容易。
有一种比较笨的办法就是扫描classpath所有的class与jar包中的class,然后用ClassLoader加载进来,然后再判断是否是给定接口的子类。但是很显然,不会使用这种方法,代价太大。
java本身也提供了一种方式来获取一个接口的子类,那就是使用java.util.ServiceLoader#load(java.lang.Class<S>) 方法,但是直接使用该方法也是不能获取到给定接口所有的子类的。
需要接口的子类以配置的方式主动注册到一个接口上,才能使用ServiceLoader进行加载到子类,并且子类需要有一个无参构造方法,用于被ServiceLoader进行实例化
下面介绍使用ServiceLoader的步骤
1、 编写Service
package com.mogujie.uni.sl;/** * Created by laibao */public interface Animal { void eat();}2、编写实现类(注意:实现类不一定要与接口在同一个工程中,可以存在于其他的jar包中)
package com.mogujie.uni.sl;/** * Created by laibao */public class Pig implements Animal { @Override public void eat() { System.out.println("Pig eating..."); }}package com.mogujie.uni.sl;/** * Created by laibao */public class Dog implements Animal { @Override public void eat() { System.out.println("Dog eating..."); }}3、 在实现类所在的工程的classpath下面的建立META-INF/services目录,该目录是固定的,一定要按照规定的名称去创建,该目录用于配置接口与实现类的映射关系
然后根据接口全名 在该目录创建一个文件,例如上面例子中接口全名是com.mogujie.uni.sl.Animal,那么就需要在实现类的工程中建立META-INF/services/com.mogujie.uni.sl.Animal这样一个文件,然后在该文件中配置该接口的实现类,如果该接口有多个实现类,一行写一个(以换行符分割),例如:
com.mogujie.uni.sl.Pigcom.mogujie.uni.sl.Dog4、接下来就能使用ServiceLoader的方法获取com.mogujie.uni.sl.Animal接口的所有子类了。
测试类如下:
package com.mogujie.uni;import com.mogujie.uni.sl.Animal;import java.util.Iterator;import java.util.ServiceLoader;/** * Created by laibao */public class TestServiceLoader { public static void main(String[] args) { ServiceLoader<Animal> serviceLoader = ServiceLoader.load(Animal.class); Iterator<Animal> animalIterator = serviceLoader.iterator(); while(animalIterator.hasNext()){ Animal animal = animalIterator.next(); animal.eat(); } }}输出如下:
Pig eating...Dog eating...ServiceLoader的原理其实很简单,就是根据给定的参数(接口)就能定位到该接口与实现类的映射配置文件的路径了,然后读取该配置文件,就能获取到该接口的子类
下面自己实现一个CustomServiceLoader与系统的ServiceLoader具有同样的功能
测试类如下:
package com.mogujie.uni;import com.mogujie.uni.sl.Animal;import java.util.List;/** * Created by laibao */public class CustomServiceLoaderTest { public static void main(String[] args) throws Exception { List<Animal> animals = CustomServiceLoader.loade(Animal.class); for (Animal animal : animals){ animal.eat(); } }}输出:
Pig eating...Dog eating...java系统定义的ServiceLoader与我们自定义的CustomServiceLoader的loade方法,它们的返回值类型是不一样的,ServiceLoader的loade方法返回的是ServiceLoader对象,ServiceLoader对象实现了Iterable接口,通过ServiceLoader的成员方法iterator();就能遍历所有的服务实例,而我们自定义的CustomServiceLoader的load方法返回的是一个List对象,直接将所有的服务实例封装在一个集合里面返回了。
系统的ServiceLoader通过返回一个Iterator对象能够做到对服务实例的懒加载只有当调用iterator.next()方法时才会实例化下一个服务实例,只有需要使用的时候才进行实例化,具体实现读者可以去阅读源码进行研究,这也是其设计的亮点之一。
以上这篇详谈ServiceLoader实现原理就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
方法文件session实现文件:memcachedsession.php实现原理(也是PHP内部session的实现原理):1.先判断客户端有没有session
JDK有个ServiceLoader类,在java.util包里,支持按约定目录/META-INF/services去找到接口全路径命名的文件,读取文件内容
一、FreeBSD下实现3D的原理。 其实这不仅仅是FreeBSD下的原理,也是整个*nix家族的原理。 3D功能的实现其实也是分层的,近似于OSI的分层模
本文实例为大家分享了Android实现图片加载进度提示的具体代码,供大家参考,具体内容如下先上图:实现原理:第一个控件的实现原理是重写ImageView的onD
一、实现方法1.纯模板语言实现2.自定义simpletag实现(本质是简化了纯模板语言的判断)二、基本原理原理都是通过django路由系统,匹配url筛选条件,