详谈即便ServiceLoader实现原理

  

在java中根据一个子类获取其父类或接口信息非常方便,但是根据一个接口获取该接口的所有实现类却没那么容易。

  

有一种比较笨的办法就是扫描类路径所有的类与jar包中类的,然后用类加载器加载进来,然后再判断是否是给定接口的子类。但是很显然,不会使用这种方法,代价太大。

  

java本身也提供了一种方式来获取一个接口的子类,那就是使用java.util.ServiceLoader #负载(java.lang.Class   

需要接口的子类以配置的方式主动注册到一个接口上,才能使用即便ServiceLoader进行加载到子类,并且子类需要有一个无参构造方法,用于被即便ServiceLoader进行实例化

  

  

        包com.mogujie.uni.sl;/* *   *由laibao   */公共接口动物{   空吃();   }      之前      

        包com.mogujie.uni.sl;/* *   *由laibao   */公共类猪实现动物{   @Override   公共空间吃(){   system . out。println(“猪吃…”);   }   }      包com.mogujie.uni.sl;/* *   *由laibao   */公共类狗实现动物{   @Override   公共空间吃(){   system . out。println(“狗吃…”);   }   }      之前      

  

然后根据接口全名在该目录创建一个文件,例如上面例子中接口全名是com.mogujie.uni.sl.Animal,那么就需要在实现类的工程中建立meta - inf/服务/com.mogujie.uni.sl.Animal这样一个文件,然后在该文件中配置该接口的实现类,如果该接口有多个实现类,一行写一个(以换行符分割),例如:

        com.mogujie.uni.sl.Pig   com.mogujie.uni.sl.Dog      之前      

  

<强>测试类如下:

        包com.mogujie.uni;   进口com.mogujie.uni.sl.Animal;   进口java.util.Iterator;   进口java.util.ServiceLoader;/* *   *由laibao   */公开课TestServiceLoader {   公共静态void main (String [] args) {   ServiceLoader即便serviceLoader=ServiceLoader.load (Animal.class);   IteratoranimalIterator=serviceLoader.iterator ();   而(animalIterator.hasNext ()) {   动物动物=animalIterator.next ();   animal.eat ();   }   }   }      之前      

输出如下:

        猪吃……   狗吃了……      之前      

即便ServiceLoader的原理其实很简单,就是根据给定的参数(接口)就能定位到该接口与实现类的映射配置文件的路径了,然后读取该配置文件,就能获取到该接口的子类

  

下面自己实现一个CustomServiceLoader与系统的即便ServiceLoader具有同样的功能
  

        包com.mogujie.uni;      进口org.apache.commons.io.IOUtils;   进口java.net.URL;   进口活动;   进口java.util.LinkedList;   进口并不知道;/* *   *由laibao   */公开课CustomServiceLoader {      公共静态最终字符串MAPPING_CONFIG_PREFIX=" meta - inf/服务”;      公共静态& lt; S>Listloade (Class服务){抛出异常   字符串mappingConfigFile=MAPPING_CONFIG_PREFIX + " + service.getName ();//由于一个接口的实现类可能存在多个jar包中的meta - inf目录下,所以下面使用getresource返回一个URL数组   EnumerationconfigFileUrls=CustomServiceLoader.class.getClassLoader () .getResources (mappingConfigFile);   如果(configFileUrls==null) {   返回null;   }   List服务=new LinkedList ();   而(configFileUrls.hasMoreElements ()) {   URL configFileUrl=configFileUrls.nextElement ();   字符串configContent=IOUtils.toString (configFileUrl.openStream ());   String[]名=configContent.split (“\ n”);   (字符串名:名){   类运行serviceClass=CustomServiceLoader.class.getClassLoader () .loadClass(名);   对象serviceInstance=serviceClass.newInstance ();   services.add ((S) serviceInstance);   }   }   返回服务;   }      }      

<强>测试类如下:

        包com.mogujie.uni;   进口com.mogujie.uni.sl.Animal;   进口并不知道;/* *   *由laibao   */公开课CustomServiceLoaderTest {   公共静态void main (String [] args){抛出异常   List动物=CustomServiceLoader.loade (Animal.class);   (动物动物:动物){   animal.eat ();   }   }   }      

详谈即便ServiceLoader实现原理