当前位置: 首页 > news >正文

Java SPI(Service Provider Interface)简介

SPI 简介

SPI 全称为(Service Provider Interface),是JDK内置的一种服务提供发现机制。

一个服务(Service)通常指的是已知的接口或者抽象类,服务提供方就是对这个接口或者抽象类的实现,然后按照SPI 标准存放到资源路径(resources)META-INF/services目录下,文件的命名为该服务接口的全限定名。如有一个服务接口:

package com.winner.spi;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public interface DemoService {
    String sayHello(String name);
}

其服务实现类为:

package com.winner.spi.impl;

import com.winner.spi.DemoService;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public class DemoServiceImpl implements DemoService {

    @Override
    public String sayHello(String name) {
        return "hello , " + name;
    }
}

那此时需要在META-INF/services中创建一个名为com.ricky.codelab.spi.DemoService的文件,其中的内容就为该实现类的全限定名:com.ricky.codelab.spi.impl.DemoServiceImpl。 
如果该Service有多个服务实现,则每一行写一个服务实现(#后面的内容为注释),并且该文件只能够是以UTF-8编码。

然后,我们可以通过ServiceLoader.load(Class class); 来动态加载Service的实现类了。

许多开发框架都使用了Java的SPI机制,如java.sql.Driver的SPI实现(mysql驱动、oracle驱动等)、common-logging的日志接口实现、dubbo的扩展实现等等。

SPI机制的约定

  • 在META-INF/services/目录中创建以Service接口全限定名命名的文件,该文件内容为Service接口具体实现类的全限定名,文件编码必须为UTF-8。
  • 使用ServiceLoader.load(Class class); 动态加载Service接口的实现类。
  • 如SPI的实现类为jar,则需要将其放在当前程序的classpath下。
  • Service的具体实现类必须有一个不带参数的构造方法。

1、项目结构

2、Service接口定义

package com.winner.spi;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public interface DemoService {
    String sayHello(String name);
}

3、Service接口实现类

本示例中DemoService有两个实现类,分别为:EnglishDemoServiceImpl和ChineseDemoServiceImpl,代码如下: 
EnglishDemoServiceImpl.java

package com.winner.spi.impl;

import com.winner.spi.DemoService;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public class EnglishDemoServiceImpl implements DemoService {

    @Override
    public String sayHello(String name) {
        return "hello , " + name;
    }
}

ChineseDemoServiceImpl.java

package com.winner.spi.impl;

import com.winner.spi.DemoService;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public class ChineseDemoServiceImpl implements DemoService {

    @Override
    public String sayHello(String name) {
        return "你好 , " + name;
    }
}

META-INF/services/配置

在src/main/resources 下创建META-INF/services/目录,并新建com.winner.spi.DemoService文件,内容如下:

#English implementation
com.winner.spi.impl.EnglishDemoServiceImpl
#Chinese implementation
com.winner.spi.impl.ChineseDemoServiceImpl

加载Service实现类

import com.winner.spi.DemoService;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public class Test {
    public static void main(String[] args) {
        ServiceLoader<DemoService> serviceLoader = ServiceLoader.load(DemoService.class);
        Iterator<DemoService> it = serviceLoader.iterator();
        while (it.hasNext()) {
            DemoService demoService = it.next();
            System.out.println("class:" + demoService.getClass().getName() 
                    + "-->" + demoService.sayHello("World"));
        }
    }
}

执行结果:

import com.winner.spi.DemoService;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
 * @author winner_0715
 * @date 2018/4/1
 */
public class Test {
    public static void main(String[] args) {
        ServiceLoader<DemoService> serviceLoader = ServiceLoader.load(DemoService.class);
        Iterator<DemoService> it = serviceLoader.iterator();
        while (it.hasNext()) {
            DemoService demoService = it.next();
            System.out.println("class:" + demoService.getClass().getName()
                    + "-->" + demoService.sayHello("World"));
        }
    }
}

 

相关文章:

  • Git 企业中常用分支管理策略
  • Linux的overcommit配置
  • 比特币现金改变了我们的生活
  • 将用户当前表空间中的表和索引迁移到另一个表空间
  • Apache OFBIZ高速上手(三)--文件夹amp;amp;配置文件介绍
  • 字符串输入
  • 06.C(指针)
  • JavaEE GenericServlet 解析
  • 算法系列15天速成——第十四天 图【上】
  • ionic3 关于屏幕方向问题
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • Confluence 6 更新目录
  • Quartz 表达式生成器
  • MongoDb进阶实践之五 MongoDB修改命令详述
  • [2]十道算法题【Java实现】
  • C学习-枚举(九)
  • java8-模拟hadoop
  • Kibana配置logstash,报表一体化
  • Laravel 菜鸟晋级之路
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • Redux 中间件分析
  • Unix命令
  • - 概述 - 《设计模式(极简c++版)》
  • 基于Android乐音识别(2)
  • 京东美团研发面经
  • 微信小程序开发问题汇总
  • 详解NodeJs流之一
  • 移动端 h5开发相关内容总结(三)
  • 怎么将电脑中的声音录制成WAV格式
  • MPAndroidChart 教程:Y轴 YAxis
  • 积累各种好的链接
  • (12)Linux 常见的三种进程状态
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (九十四)函数和二维数组
  • (转)ORM
  • (转)visual stdio 书签功能介绍
  • .NET Core 成都线下面基会拉开序幕
  • .NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式
  • .NET 使用 XPath 来读写 XML 文件
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .NET中的Exception处理(C#)
  • .pyc文件是什么?
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • /etc/X11/xorg.conf 文件被误改后进不了图形化界面
  • @RestController注解的使用
  • @在php中起什么作用?
  • []sim300 GPRS数据收发程序
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [1]-基于图搜索的路径规划基础
  • [20150707]外部表与rowid.txt
  • [BJDCTF2020]The mystery of ip
  • [C++]:for循环for(int num : nums)