博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JDK-SPI简介【一】
阅读量:4208 次
发布时间:2019-05-26

本文共 3040 字,大约阅读时间需要 10 分钟。

1.什么是SPI?

SPI:Service Provider Interface,是JDK提供的为某个接口寻找服务实现的机制。为了实现不对实现类进行硬编码,在程序里动态指明。

2.使用场景?

2.1 common-logging

apache最早提供的日志的门面接口。只有接口,没有实现。具体方案由各提供商实现, 发现日志提供商是通过扫描 META-INF/services/org.apache.commons.logging.LogFactory配置文件,通过读取该文件的内容找到日志提工商实现类。只要我们的日志实现里包含了这个文件,并在文件里制定 LogFactory工厂接口的实现类即可。

2.2 JDBC

META-INF.services包下有个java.sql.Driver文件:

com.mysql.jdbc.Driver
com.mysql.fabric.jdbc.FabricMySQLDriver

其中com.mysql.jdbc.Driver类是实现了java.sql.Driver接口,下面那com.mysql.fabric.jdbc.FabricMySQLDriver才是真正的实现类

 

3.例子:

3.1接口:

package com.test.spi;public interface HelloInterface {    public void sayHello();}

3.2实现类:

public class ImageHello implements HelloInterface {    @Override    public void sayHello() {        System.out.println("Image Hello");    }}
public class TextHello implements HelloInterface {    @Override    public void sayHello() {        System.out.println("Text Hello.");    }}

3.3 文件

在src路径下的META-INF/services/com.test.spi.HelloInterface

com.test.spi.impl.TextHellocom.test.spi.impl.ImageHello

3.4 Main方法

public class SPIMain {    public static void main(String[] args) {        ServiceLoader
loaders = ServiceLoader.load(HelloInterface.class); for (HelloInterface in : loaders) { in.sayHello(); } }}

3.5 运行结果:

Text Hello.

Image Hello

4.原理分析

4.1ServiceLoader实现了Iterable这个接口,因此可以在遍历的时候,重新进行lazy加载。

public final class ServiceLoader    implements Iterable{    private static final String PREFIX = "META-INF/services/";    // The class or interface representing the service being loaded    private final Class service;    // The class loader used to locate, load, and instantiate providers    private final ClassLoader loader;    // The access control context taken when the ServiceLoader is created    private final AccessControlContext acc;    // Cached providers, in instantiation order    private LinkedHashMap
providers = new LinkedHashMap<>(); // The current lazy-lookup iterator private LazyIterator lookupIterator;}

4.2

private class LazyIterator        implements Iterator    {        private S nextService() {            if (!hasNextService())                throw new NoSuchElementException();            String cn = nextName;            nextName = null;            Class
c = null; try { //延迟加载 c = Class.forName(cn, false, loader); } catch (ClassNotFoundException x) { fail(service, "Provider " + cn + " not found"); } if (!service.isAssignableFrom(c)) { fail(service, "Provider " + cn + " not a subtype"); } try { S p = service.cast(c.newInstance()); providers.put(cn, p); return p; } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated", x); } throw new Error(); // This cannot happen } }

参考:

1.

转载地址:http://xpqli.baihongyu.com/

你可能感兴趣的文章
MySQL修改root密码的4种方法
查看>>
CentOS Apache 环境+php,解决php直接输出源码
查看>>
python 安装scipy 报错:Microsoft Visual C++ 14.0 is required
查看>>
python 报错Microsoft Visual C++ 14.0 is required
查看>>
requests.exceptions.TooManyRedirects: Exceeded 30 redirects.
查看>>
爬取《战狼2》电影短评论,生成图云
查看>>
linux 操作命令: cp
查看>>
adb 命令2
查看>>
matplotlib中文坐标轴和标题显示
查看>>
使用K-S检验一个数列是否服从正态分布、两个数列是否服从相同的分布
查看>>
网络传输层在网络中的地位
查看>>
网络中进程通信的标识
查看>>
TCP与UDP的区别
查看>>
ps aux tailf netstat命令
查看>>
语音信号处理-矢量量化VQ
查看>>
语音信号处理-动态时间规整DTW
查看>>
语音信号处理-HMM1
查看>>
python 多线程
查看>>
Python UnicodeEncodeError: 'gbk' codec can't encode character 解决方法
查看>>
Google 渗透工具-搜集信息
查看>>