SPI简单解析

 

什么是SPI 

一种服务加载方式,全名为Service Provider Interface,Service提供者接口

如果我们要抽象里面的模块,在面对对象编程当中,我们模块之间,一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。
一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。
为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。所以SPI的核心思想就是解耦

 

通俗例子解释:

例子:
JDK中有支持音乐播放,假设只支持mp3的播放,有些厂商想在这个基础之上支持mp4播放,有的想支持mp5播放,
而这些厂商都是第三方厂商,如果没有提供SPI这种实现标准,那就只有修改JAVA的源代码了。
有了SPI标准,JDK的爸爸SUN公司只需要提供一个播放接口,在实现播放的功能上通过ServiceLoad的方式加载服务,
那么第三方只需要实现这个播放接口,再按SPI标准的约定进行打包,再放到classpath下面就OK了

 

SPI的机制约定:

1)         在jar包的META-INF/services/目录中创建以接口全限定名命名的文件该文件内容为Api具体实现类的全限定名

2)         服务调用方用java.util.ServiceLoader,用服务接口为参数,去动态加载具体的实现类到JVM中

3)         如SPI的实现类为Jar则需要放在主程序classPath中

4)         定义服务的通用接口,针对通用的服务接口,提供具体的实现类

 

 

 

 

 

//通用接口,
public interface SendMessage {
    void send(String msg);
}

 

package com.quan.spi.emailimp;

import com.quan.spi.api.SendMessage;


//通用接口的实现类1
public class SendMessageEmail implements SendMessage {

    @Override
    public void send(String msg) {
        System.out.println("send  " + msg +"   use email");

    }
}

 

package com.quan.spi.phoneimp;

import com.quan.spi.api.SendMessage;


//通用接口的实现类2
public class SendMessagePhone implements SendMessage {
    @Override
    public void send(String msg) {
        System.out.println("send  " +msg +"  use phone");
    }
}

 

//通过工厂模式去获得sendmessage
public class SendMessageFactory {
    public SendMessageFactory() {
    }

    public static SendMessage getsend(){
        SendMessage sendMessage = null;
        ServiceLoader<SendMessage> sendMessages = ServiceLoader.load(SendMessage.class);
        Iterator iterator = sendMessages.iterator();
        while (iterator.hasNext()){
            sendMessage = (SendMessage) iterator.next();
            sendMessage.send("quan");
        }
        return sendMessage;
    }
}

 

META-INF/services:

名字为:com.quan.spi.api.SendMessage

com.quan.spi.emailimp.SendMessageEmail
com.quan.spi.phoneimp.SendMessagePhone

 

测试:

package com.quan.spi;

import com.quan.spi.api.SendMessage;
import org.junit.Test;

import java.util.ServiceLoader;

public class TestMessage {
    @Test
    public  void Test(){
        SendMessageFactory.getsend();
    }

    @Test
    public void Test2(){
        ServiceLoader<SendMessage> sendMessages = ServiceLoader.load(SendMessage.class);
        for (SendMessage s : sendMessages) {
            s.send("quanquan");
        }
    }



}

 

posted @ 2020-09-01 17:39  小丑quan  阅读(370)  评论(0)    收藏  举报