java.util.ServiceLoader demo

本文介绍了一种服务声明与实现分离的机制,通过定义接口和服务提供者实现,可以在运行时动态选择服务实现。利用ServiceLoader加载服务提供者,实现服务的灵活配置与扩展。

首先引用API中的说明文档:

 

一个简单的服务提供者加载设施。

 

服务 是一个熟知的接口和类(通常为抽象类)集合。服务提供者 是服务的特定实现。提供者中的类通常实现接口,并子类化在服务本身中定义的子类。服务提供者可以以扩展的形式安装在 Java 平台的实现中,也就是将 jar 文件放入任意常用的扩展目录中。也可通过将提供者加入应用程序类路径,或者通过其他某些特定于平台的方式使其可用。

 

为了加载,服务由单个类型表示,也就是单个接口或抽象类。(可以使用具体类,但建议不要这样做。)一个给定服务的提供者包含一个或多个具体类,这些类扩展了此服务类型 ,具有特定于提供者的数据和代码。提供者类 通常不是整个提供者本身而是一个代理,它包含足够的信息来决定提供者是否能满足特定请求,还包含可以根据需要创建实际提供者的代码。提供者类的详细信息高度特定于服务;任何单个类或接口都不能统一它们,因此这里没有定义任何这种类型。此设施唯一强制要求的是,提供者类必须具有不带参数的构造方法,以便它们可以在加载中被实例化。

 

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

 

....还有其他的一些就不拷贝过来了。

 

 

从说明中可以看出,这个机制允许服务的声明与实现的分离,具体使用哪个实现可以在运行时才决定,使用哪个实现取决于是否部署了该实现。下面是个简单的demo。

 

1、首先定义一个表示服务的接口:

package learn.serviceLoader.service;

import java.util.ServiceLoader;

public abstract class SimpleService {
	public abstract void doService();

	private static boolean isInit = false;
	private static SimpleService service = null;

	public static final SimpleService getService() {
		if (!isInit) {
			ServiceLoader<SimpleService> serviceLoader = ServiceLoader
					.load(SimpleService.class);
			for (SimpleService s : serviceLoader) {
				service = s;
				break;
			}

			isInit = true;
		}

		return service;
	}
}

 

此接口定义了服务的能力,同时提供了工厂方法来获取服务的实例。这个工厂方法就是通过此机制来查找服务的实现的。

 

 

2、实现服务提供者。

package learn.serviceLoader.serviceimpl;

import learn.serviceLoader.service.SimpleService;

public class StandarService extends SimpleService {

	@Override
	public void doService() {
		System.out
				.println("i am standar service, i implement SimpleService, so you get here .");
	}
}

 就是实现服务接口的方法。

 

 

3、在服务提供者jar中下配置:

    a、建立一个META-INF文件夹,在META-INF文件夹下建立一个services文件夹;

    b、在services文件夹下建立服务配置文件,如:learn.serviceloader.service.SimpleService

        里面的内容就是提供者的全限定类名:learn.serviceLoader.serviceimpl.StandarService    # comment

 

 

4、服务的使用者:

package learn.serviceLoader.test;

import learn.serviceLoader.service.SimpleService;

public class TestServiceLoader {

	public static void main(String[] args) {
		SimpleService service = SimpleService.getService();
		service.doService();
		
		SimpleService service2 = SimpleService.getService();
		service2.doService();
	}
}

 服务的使用者通过服务接口的工厂方法来获取服务,使用者并不知道、也不需要知道使用的是哪个服务提供者。

 

 

对于复杂的使用,应该将服务的声明放在单独的api.jar包,不同的实现放在不同的jar,部署时只需要部署api.jar和特定的提供者jar包。此机制还支持  “reload ()   清除此加载器的服务者缓存,以重载所有服务者。”,应该可以预留方法,实现动态切换服务提供者。

 

 

这是个简单又强大的机制,可以方便地实现服务声明与实现的分离。

 

scala: ## Exception when compiling 43 sources to D:\scala\scala-demo\target\classes java.lang.NullPointerException sbt.internal.inc.classpath.DualLoader.getResources(DualLoader.scala:100) java.lang.ClassLoader.getResources(ClassLoader.java:1138) java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:348) java.util.ServiceLoader$LazyIterator.access$600(ServiceLoader.java:323) java.util.ServiceLoader$LazyIterator$1.run(ServiceLoader.java:396) java.util.ServiceLoader$LazyIterator$1.run(ServiceLoader.java:395) java.security.AccessController.doPrivileged(Native Method) java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:398) java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474) scala.collection.convert.JavaCollectionWrappers$JIteratorWrapper.hasNext(JavaCollectionWrappers.scala:46) scala.collection.immutable.List.prependedAll(List.scala:152) scala.collection.IterableOnceOps.toList(IterableOnce.scala:1446) scala.collection.IterableOnceOps.toList$(IterableOnce.scala:1446) scala.collection.AbstractIterator.toList(Iterator.scala:1306) sbt.internal.inc.AnalyzingCompiler.loadService(AnalyzingCompiler.scala:316) sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:89) sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:196) scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18) sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:252) sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:186) sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:166) sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:241) sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:166) sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:214) sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:542) sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1$adapted(IncrementalCompilerImpl.scala:542) sbt.internal.inc.Incremental$.$anonfun$apply$3(Incremental.scala:182) sbt.internal.inc.Incremental$.$anonfun$apply$3$adapted(Incremental.scala:180) sbt.internal.inc.Incremental$$anon$2.run(Incremental.scala:458) sbt.internal.inc.IncrementalCommon$CycleState.next(IncrementalCommon.scala:117) sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:56) sbt.internal.inc.IncrementalCommon$$anon$1.next(IncrementalCommon.scala:52) sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:263) sbt.internal.inc.Incremental$.$anonfun$incrementalCompile$8(Incremental.scala:413) sbt.internal.inc.Incremental$.withClassfileManager(Incremental.scala:500) sbt.internal.inc.Incremental$.incrementalCompile(Incremental.scala:400) sbt.internal.inc.Incremental$.apply(Incremental.scala:208) sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:542) sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileIncrementally$1(IncrementalCompilerImpl.scala:496) sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:332) sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:433) sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:137) org.jetbrains.jps.incremental.scala.local.SbtCompiler.$anonfun$doCompile$3(SbtCompiler.scala:87) scala.util.Try$.apply(Try.scala:217) org.jetbrains.jps.incremental.scala.local.SbtCompiler.doCompile(SbtCompiler.scala:85) org.jetbrains.jps.incremental.scala.local.SbtCompiler.compile(SbtCompiler.scala:17) org.jetbrains.jps.incremental.scala.local.LocalServer.doCompile(LocalServer.scala:49) org.jetbrains.jps.incremental.scala.local.LocalServer.compile(LocalServer.scala:28) org.jetbrains.jps.incremental.scala.remote.Main$.compileLogic(Main.scala:209) org.jetbrains.jps.incremental.scala.remote.Main$.$anonfun$handleCommand$1(Main.scala:190) org.jetbrains.jps.incremental.scala.remote.Main$.decorated$1(Main.scala:177) org.jetbrains.jps.incremental.scala.remote.Main$.handleCommand(Main.scala:187) org.jetbrains.jps.incremental.scala.remote.Main$.serverLogic(Main.scala:160) org.jetbrains.jps.incremental.scala.remote.Main$.nailMain(Main.scala:100) org.jetbrains.jps.incremental.scala.remote.Main.nailMain(Main.scala) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:498) com.facebook.nailgun.NGSession.runImpl(NGSession.java:312) com.facebook.nailgun.NGSession.run(NGSession.java:198) 这是什么问题
最新发布
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值