Java 一个特殊的类 ServiceLoader 详解

  ServiceLoader与ClassLoader是Java中2个即相互区别又相互联系的加载器.JVM利用ClassLoader将类载入内存,这是一个类声明周期的第一步(一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况)。详情请参阅:详解Java类的生命周期

ServiceLoader又是什么呢?ServiceLoader:一个简单的服务提供者加载设施。服务 是一个熟知的接口和类(通常为抽象类)集合。服务提供者 是服务的特定实现。提供者中的类通常实现接口,并子类化在服务本身中定义的子类。服务提供者可以以扩展的形式安装在 Java 平台的实现中,也就是将 jar 文件放入任意常用的扩展目录中。也可通过将提供者加入应用程序类路径,或者通过其他某些特定于平台的方式使其可用。……唯一强制要求的是,提供者类必须具有不带参数的构造方法,以便它们可以在加载中被实例化。

通过在资源目录META-INF/services中放置提供者配置文件 来标识服务提供者。文件名称是服务类型的完全限定二进制名称。该文件包含一个具体提供者类的完全限定二进制名称列表,每行一个。忽略各名称周围的空格、制表符和空行。注释字符为'#'('\u0023', NUMBER SIGN);忽略每行第一个注释字符后面的所有字符。文件必须使用 UTF-8 编码。 

以延迟方式查找和实例化提供者,也就是说根据需要进行。服务加载器维护到目前为止已经加载的提供者缓存。每次调用 iterator 方法返回一个迭代器,它首先按照实例化顺序生成缓存的所有元素,然后以延迟方式查找和实例化所有剩余的提供者,依次将每个提供者添加到缓存。可以通过 reload 方法清除缓存。

    首先这个类是 final 不能继承的。经常我们会有一个接口许多实现类,比如: UserDao接口有UserDaoImpl1 、UserDaoImpl2 ....等多个实现。这时候我们只能自己new,但是有了ServiceLoader<S>就非常方便,他会帮我们把实现类放入一个集合方便遍历 。但是这又有什么用呢,这个配合命令模式就有大用了:

    首先在src文件夹下面创建一个META-INF文件夹里面再创建一个services文件夹里面放着一个你接口的全类名 的文件 比如 org.web.UserDao  

Java 一个特殊的类 ServiceLoader<S> 详解_第1张图片

而文件里面放着这个接口的实现类 比如 org.web.UserDaoImpl1  org.web.UserDaoImpl2

Java 一个特殊的类 ServiceLoader<S> 详解_第2张图片

然后一句代码就OK了 

ServiceLoader<UserDao>list=ServiceLoader.load(UserDao.class); 

然后就可以遍历list了 

接下来介绍一下这个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();
  }
} 

这样以后要扩展就多写一个实现类,多加一项配置,更好的体现了面向对象的思想。


参考:http://blog.csdn.net/lmh12506/article/details/50428860

    http://www.cnblogs.com/nimendezaige/p/4866468.html




你可能感兴趣的:(ServiceLoader)