Java的ServiceLoader(java.util.ServiceLoader,服务加载器)不是Java9中才出现的,Java6就开始使用了。这里的服务,可以简单的理解为Java接口,加载器加载的是接口的实现类(也可以说成服务是实现了接口的类)。在Java9以前主要用于实现spi机制,也就是动态加载实现类。Java9赋予了它新的功能,这篇文章简单讲一下ServiceLoader的使用。
面向对象编程会将how和what分开,所以有接口和实现:接口定义了what,实现阐明了how。
SPI 机制
关于spi的介绍网上能搜出来一大把,很多还讲得不错。
如果你懒得去搜,这里简单演示一下它的用法。定义了一个接口 IMovable,表示一种可以移动的特征。
package com.j11.spi;
public interface IMovable {
void move();
}
实现类可以有一个或多个。为了演示,这里实现两个:
package com.j11.spi;public class Human implements IMovable {@Overridepublic void move() {System.out.println("human steps……");}}
package com.j11.spi;public class Car implements IMovable {@Overridepublic void move() {System.out.println("Car wheels……");}}
ServiceLoader要求被加载服务的描述符文件必须在/META-INF/services目录下。创建该目录,并在该目录下创建文件com.j11.spi.IMovable,内容如下:
com.j11.spi.Humancom.j11.spi.Car
每个实现类写一行。
SPI全称Service Provider Interface,即服务提供方接口,创建一个main方法类,方法体如下:
ServiceLoader shouts = ServiceLoader.load(IMovable.class);for (IMovable s : shouts) {s.move();if (s instanceof Car) {System.out.println("match");}}
输出
human steps……Car wheels……match
IDEA 内置对spi机制的支持,如果接口和描述符不匹配则会立即警告。
Java9+模块对spi的支持
Java9+中,依然可以写出上面这种代码。不过显示模块化的话,可以使用provides、uses和with关键字(注意,它们和其他的模块关键字一样都不是保留字,可以用做变量名称),provides就是spi中的p。
创建一个模块,只包含服务接口和服务提供接口:
package com.j11.spi;public interface IService {String getName();void serve();void halt();}package com.j11.spi;public interface IServiceProvider {IService provide();}module service {exports com.j11.spi;}
创建模块实现接口:
package com.j11.service.impl;import com.j11.spi.IService;public class Server1 implements IService {@Overridepublic String getName() {return "s1";}@Overridepublic void serve() {System.out.println("s1 is serving");}@Overridepublic void halt() {System.out.println("s1 stopped");}}package com.j11.service.impl;import com.j11.spi.IService;public class Server2 implements IService {@Overridepublic String getName() {return "s2";}@Overridepublic void serve() {System.out.println("s2 is serving");}@Overridepublic void halt() {System.out.println("s2 stopped");}}
服务提供方实现:
package com.j11.provider.impl;import com.j11.service.impl.Server1;import com.j11.spi.IService;import com.j11.spi.IServiceProvider;public class S1Provider implements IServiceProvider {@Overridepublic IService provide() {return new Server1();}}package com.j11.provider.impl;import com.j11.service.impl.Server2;import com.j11.spi.IService;import com.j11.spi.IServiceProvider;public class S2Provider implements IServiceProvider {@Overridepublic IService provide() {return new Server2();}}
模块描述符中暴露服务,使用provides IX with Y,Z:
module provider {requires transitive service;provides com.j11.spi.IServiceProvider with com.j11.provider.impl.S1Provider, com.j11.provider.impl.S2Provider;}
最后,应用模块要使用服务,用到了uses关键字:
module customer {requires provider;uses com.j11.spi.IServiceProvider;}
启动应用:
package com.j11.spi.customer;import com.j11.spi.IService;import com.j11.spi.IServiceProvider;import java.util.ServiceLoader;public class Customer {public static void main(String[] args) {ServiceLoader sl = ServiceLoader.load(IServiceProvider.class);for (IServiceProvider provider : sl) {IService server = provider.provide();server.serve();if (server.getName().equals("s2")) {server.halt();}}}}
输出
s1 is servings2 is servings2 stopped
希望今天的内容对大家有帮助!