Java_SPI思想

研究SpringBoot源码的时候偶遇SpringFactoriesLoader,即SPI思想(也可以说是一种SPI机制)

1、SPI 思想是什么?

SPI 的全名为 Service Provider Interface 。SPI 思想 也可以叫做 SPI机制 ,它就是为某个接口寻找服务实现的机制

2、为什么会有这个东西?

​ 这个东西主要微服务用的多,因为这个思想是针对厂商或者插件的。在java.util.ServiceLoader 的API文档里有比较详细的介绍。

​ 简单的总结下 Java SPI 机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。

​ 为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。 Java SPI 就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外(通过约定的配置文件),在模块化设计中这个机制尤其重要。

​ 同时起到解耦的作用。

3、SPI 具体怎么实现呢?

​ 为了使用Java SPI ,需要遵循一种约定,该约定为: 当服务的提供者(厂商或者插件),提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口全类名命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

4、话不多说,代码走起

4.1、支付案例

一个订单系统有一个支付模块,是基于接口编程的。支付的实现可能是基于支付宝支付、也可以基于微信支付等等

建立一个maven项目:父项目 java-spi、子项目(包含四个模块) main-pay、services-common、wx-pay、zfb-pay

img

各个模块细节:

http://note.youdao.com/yws/public/resource/4a3ed872ace93dc1115e9af8c1dd1aba/xmlnote/4CE2A5659721477692BC6E0A0A3217B3/15506

服务接口定义:

package com.xd.service;

/**
 * @author dee
 * @create 2020-11-19 0:59
 */
public interface PayService {
    public void pay();
}

微信厂商实现模块:

package com.xd.impl;

import com.xd.service.PayService;

/**
 * @author dee
 * @create 2020-11-19 1:15
 */
public class WxPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("微信支付!");
    }
}

支付宝厂商实现模块:

package com.xd.impl;

import com.xd.service.PayService;

/**
 * @author dee
 * @create 2020-11-19 1:01
 */
public class ZfbPayService implements PayService {
    @Override
    public void pay() {
        System.out.println("支付宝支付!");
    }
}

主程序模块:

package com.xd;

import com.xd.impl.WxPayService;
import com.xd.service.PayService;

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

/**
 * @author dee
 * @create 2020-11-19 1:17
 */
public class PayTest {

    public static void main(String[] args) {
        //通过load方法新建对象
        ServiceLoader<PayService> serviceLoader = ServiceLoader.load(PayService.class);
        
        Iterator<PayService> iterator = serviceLoader.iterator();
        while (iterator.hasNext()){
            PayService payService = iterator.next();
            payService.pay();
        }
    }
}

当需要使用微信支付的时候,只需要在主程序pom文件导入微信模块的pom依赖即可

<dependency>
    <groupId>org.example</groupId>
    <artifactId>wx-pay</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

需要注意的是:厂商接口实现模块,有一个路径为META-INF/services/文件名为 com.xd.service.PayService的文件,里面内容为微信实现类的全类名,即SPI约定

com.xd.impl.WxPayService

执行主程序输出:

微信支付!

当需要使用支付宝支付只需要导入支付宝实现模块pom依赖即可

<dependency>
    <groupId>org.example</groupId>
    <artifactId>zfb-pay</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

执行主程序输出:

支付宝支付!

下面这些技术也有使用SPI思想,这里就不在这里扩展了!

4.2、DriverManager

DriverManager是jdbc里管理和注册不同数据库driver的工具类。

4.3、Spring

Spring中运用到spi思想的地方也有很多,下面随便列举几个

scan、scop、ConfigurableBeanFactory

4.4、SPI思想可是SpringBoot的灵魂

SpringFactoriesLoader工具类

4.5、Hotspot

参考资料:

https://zhuanlan.zhihu.com/p/28909673

https://blog.csdn.net/sigangjun/article/details/79071850?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.not_use_machine_learn_pai

https://www.bilibili.com/video/BV13A411B7JH?from=search&seid=17307742882483866414

posted @ 2020-11-20 21:12  zombiesChen  阅读(302)  评论(0编辑  收藏  举报