ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个java类的完整的生命周期会经历加载、链接、初始化、使用、和卸载五个阶段,固然也有在加载或者链接以后没有被初始化就直接被使用的状况)。详情请参阅:详解Java类的生命周期 html
那ServiceLoader又是什么呢?ServiceLoader:一个简单的服务提供者加载设施。服务 是一个熟知的接口和类(一般为抽象类)集合。服务提供者 是 服务的特定实现。提供者中的类一般实现接口,并子类化在服务自己中定义的子类。服务提供者能够以扩展的形式安装在 Java 平台的实现中,也就是将 jar 文件放入任意经常使用的扩展目录中。也可经过将提供者加入应用程序类路径,或者经过其余某些特定于平台的方式使其可用。……惟一强制要求的是,提供者类必须具 有不带参数的构造方法,以便它们能够在加载中被实例化。 java
经过在资源目录META-INF/services中放置提供者配置文件 来标识服务提供者。文件名称是服务类型的彻底限定二进制名称。该文件包含一个具体提供者类的彻底限定二进制名称列表,每行一个。忽略各名称周围的空格、制表符和空行。注释字符为'#'('\u0023', NUMBER SIGN);忽略每行第一个注释字符后面的全部字符。文件必须使用 UTF-8 编码。
web
以延迟方式查找和实例化提供者,也就是说根据须要进行。服务加载器维护到目前为止已经加载的提供者缓存。每次调用 iterator 方法返回一个迭代器,它首先按照实例化顺序生成缓存的全部元素,而后以延迟方式查找和实例化全部剩余的提供者,依次将每一个提供者添加到缓存。能够经过 reload 方法清除缓存。 缓存
首 先这个类是 final 不能继承的。常常咱们会有一个接口许多实现类,好比: UserDao接口有UserDaoImpl1 、UserDaoImpl2 ....等多个实现。这时候咱们只能本身new,可是有了ServiceLoader<S>就很是方便,他会帮咱们把实现类放入一个集合方便 遍历 。可是这又有什么用呢,这个配合命令模式就有大用了: 编码
首先在src文件夹下面建立一个META-INF文件夹里面再建立一个services文件夹里面放着一个你接口的全类名 的文件 好比 org.web.UserDao spa
而文件里面放着这个接口的实现类 好比 org.web.UserDaoImpl1 org.web.UserDaoImpl2 .net
而后一句代码就OK了
code
ServiceLoader<UserDao>list=ServiceLoader.load(UserDao.class);
而后就能够遍历list了 htm
接下来介绍一下这个ServiceLoader的经常使用用途 对象
好比咱们要判断传过来来的值是什么类型的
if(a == 1){ //处理的事 } else if(a == 2){ //处理的事 }else if(a == 2){ //处理的事 }
这样的话之后多一种状况就多一种else if 不利于扩展
因此能够把每一个if 作成命令模式
首先建立一个借口 Interface
public interface inte{ //判断是否用这个实现类的解决方案 public boolean is(int num); //解决方案 public void result(); }
而后建立2个实现类
public class inteImpl1 implements inte{ public boolean is(int num){ //代替了多重if if(num == 1) return true; return false; } public void result(){ //这里是 1的解决方案 } }
public class inteImpl2 implements inte{ public boolean is(int num){ //代替了多重if if(num == 2) return true; return false; } public void result(){ //这里是 2的解决方案 } }
写好services里面的对应接口和实现类的全类名:
xx.xx.inteImpl1 xx.xx.inteImpl2
而后就可使用了:
ServiceLoader<Inte> list=ServiceLoader.load(Inte.class); for(Inte in :list){ if(in.is(1)){ in.result(); } }
这样之后要扩展就多写一个实现类,多加一项配置,更好的体现了面向对象的思想。