在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); Iterator animalIterator=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实现原理