JDK的SPI
2015-12-14 17:26
134 查看
一个服务(service)通常指的是已知的接口或者抽象类,服务提供方就是对这个接口或者抽象类的实现,然后按spi标准存放到资源路径META-INF/services目录下,文件的命名为该服务接口的全限定名。如有一个服务接口com.test.Service,其服务实现类为com.test.ChildService,那此时需要在META-INF/services中放置文件com.test.Service,其中的内容就为该实现类的全限定名com.test.ChildService,有多个服务实现,每一行写一个服务实现,#后面的内容为注释,并且该文件只能够是以UTF-8编码。
这种实现方式,感觉和我们通常的开发方式差不多,都是定义一个接口,然后子类实现父类中定义的方法,为什么要搞这么一套标准以及单独搞一个配置文件?这种方式主要是针对不同的服务提供厂商,对不同场景的提供不同的解决方案制定的一套标准,举个简单的例子,如现在的JDK中有支持音乐播放,假设只支持mp3的播放,有些厂商想在这个基础之上支持mp4的播放,有的想支持mp5,而这些厂商都是第三方厂商,如果没有提供SPI这种实现标准,那就只有修改JAVA的源代码了,那这个弊端也是显而易见的,也就是不能够随着JDK的升级而升级现在的应用了,而有了SPI标准,SUN公司只需要提供一个播放接口,在实现播放的功能上通过ServiceLoad的方式加载服务,那么第三方只需要实现这个播放接口,再按SPI标准进行打包成jar,再放到classpath下面就OK了,没有一点代码的侵入性。
如xml-parse等都属于spi,我自己实践了一下,示例如下:
定义接口
Java代码
package spi;
/**
* Service Provider Interface
* META-INF\service\$interface full name
* 内容为借口实现类全名
* @author liwenj
*/
public interface Developer {
public String getPrograme();
}
实现接口
Java代码
package spi;
public class JavaDeveloper implements Developer {
@Override
public String getPrograme() {
return "Java";
}
}
实现接口的同时,需要在MANIFEST中声明实现
在META-INF\service目录下 创建文件,以接口全名为名,如"spi.Developer"
内容就是实现类的全名,可以存在多个
注意:在META-INF\service中声明好接口实现后,要打成一个jar包导入到工程的classpath中。jdk需要在Jar文件中的META-INF\service目录中搜索
使用实现
Java代码
package spi;
import java.util.ServiceLoader;
public class DeveloperClient {
public ServiceLoader<Developer> serviceloader = ServiceLoader.load(Developer.class);
public static void main(String[] arg) {
DeveloperClient devClient = new DeveloperClient();
Developer dev = devClient.getDeveloper();
System.out.println(dev.getPrograme());
}
private Developer getDeveloper(){
Developer lastdev = null;
for(Developer dev : serviceloader) {
System.out.println("out." + dev.getPrograme());
lastdev = dev;
}
return lastdev;
}
}
这种实现方式,感觉和我们通常的开发方式差不多,都是定义一个接口,然后子类实现父类中定义的方法,为什么要搞这么一套标准以及单独搞一个配置文件?这种方式主要是针对不同的服务提供厂商,对不同场景的提供不同的解决方案制定的一套标准,举个简单的例子,如现在的JDK中有支持音乐播放,假设只支持mp3的播放,有些厂商想在这个基础之上支持mp4的播放,有的想支持mp5,而这些厂商都是第三方厂商,如果没有提供SPI这种实现标准,那就只有修改JAVA的源代码了,那这个弊端也是显而易见的,也就是不能够随着JDK的升级而升级现在的应用了,而有了SPI标准,SUN公司只需要提供一个播放接口,在实现播放的功能上通过ServiceLoad的方式加载服务,那么第三方只需要实现这个播放接口,再按SPI标准进行打包成jar,再放到classpath下面就OK了,没有一点代码的侵入性。
如xml-parse等都属于spi,我自己实践了一下,示例如下:
定义接口
Java代码
package spi;
/**
* Service Provider Interface
* META-INF\service\$interface full name
* 内容为借口实现类全名
* @author liwenj
*/
public interface Developer {
public String getPrograme();
}
实现接口
Java代码
package spi;
public class JavaDeveloper implements Developer {
@Override
public String getPrograme() {
return "Java";
}
}
实现接口的同时,需要在MANIFEST中声明实现
在META-INF\service目录下 创建文件,以接口全名为名,如"spi.Developer"
内容就是实现类的全名,可以存在多个
注意:在META-INF\service中声明好接口实现后,要打成一个jar包导入到工程的classpath中。jdk需要在Jar文件中的META-INF\service目录中搜索
使用实现
Java代码
package spi;
import java.util.ServiceLoader;
public class DeveloperClient {
public ServiceLoader<Developer> serviceloader = ServiceLoader.load(Developer.class);
public static void main(String[] arg) {
DeveloperClient devClient = new DeveloperClient();
Developer dev = devClient.getDeveloper();
System.out.println(dev.getPrograme());
}
private Developer getDeveloper(){
Developer lastdev = null;
for(Developer dev : serviceloader) {
System.out.println("out." + dev.getPrograme());
lastdev = dev;
}
return lastdev;
}
}
相关文章推荐
- Java泛型详解
- spring结合mockito
- 使用eclipse生成文档(javadoc)主要有三种方法:
- Eclipse热交换代码失败
- Java Thread.join()详解
- java.lang.OutOfMemoryError异常解决方法
- 深度分析Java的ClassLoader机制(源码级别)
- Eclipse 运行弹出A Java Exception has occurred.并报错Exception in thread
- Java中throws与throw的区别
- Java基础编程之统计字符个数
- java十分钟速懂知识点——System类
- javaweb页面嵌入天气显示
- springmvc url 路径映射
- java基础之 多态
- 从头认识java-13.7 什么时候使用泛型?
- spring依赖注入理解
- Eclipse解决启动慢
- eclipse java.lang.OutOfMemoryError: Java heap space 解决方案
- Spring中AOP的使用
- 启动异常java.lang.IllegalAccessError: tried to access method DefaultSingletonBeanRegistry