SPI

作者: 越狱的灵感 | 来源:发表于2022-06-07 09:30 被阅读0次

    前言

    查看mysql-connector-java-5.1.47.jar包,可以看到


    1.png

    可以看到有一个java.sql.Driver这样的文件,这个是jdk给数据库厂商定的协议,第三方厂商可以做相应的实现来对接自己的服务。

    定义

    API (Application Programming Interface)在大多数情况下,都是实现方制定接口并完成对接口的实现,调用方仅仅依赖接口调用,且无权选择不同实现。 从使用人员上来说,API 直接被应用开发人员使用。
    SPI (Service Provider Interface)是调用方来制定接口规范,提供给外部来实现,调用方在调用时则选择自己需要的外部实现。 从使用人员上来说,SPI 被框架扩展人员使用。

    说人话:
    API:自己定义自己实现
    SPI:自己定义别人实现,调用的时候动态加载

    2.png

    试用

    1,首先定义SPI标准接口,你可以理解为类似于jdk的java.sql.Driver


    3.png

    代码:

    public interface ILiveCdn {
        void upload(String path);
        void play(String video);
    }
    

    2,实现标准接口,你可以理解为类似于mysql-connector-java-xxx.jar


    4.png
    public class AliyunLiveCdnImpl implements ILiveCdn {
        protected static final Logger LOGGER = LoggerFactory.getLogger(AliyunLiveCdnImpl.class);
     
        @Override
        public void upload(String path) {
            LOGGER.info("AliyunLiveCdn upload:{}", path);
        }
     
        @Override
        public void play(String video) {
            LOGGER.info("AliyunLiveCdn play:{}", video);
        }
    }
     
    public class ChinanetLiveCdnImpl implements ILiveCdn {
        protected static final Logger LOGGER = LoggerFactory.getLogger(ChinanetLiveCdnImpl.class);
     
        @Override
        public void upload(String path) {
            LOGGER.info("ChinanetLiveCdn upload:{}", path);
        }
     
        @Override
        public void play(String video) {
            LOGGER.info("ChinanetLiveCdn play:{}", video);
        }
    }
    

    3,调用方,可以理解为调用jdk的jdbc服务的开发者


    5.png

    代码:

    public class SpiClientTest {
        public static void main(String[] args) {
            test1();
        }
     
        private static void test1() {
            ServiceLoader<ILiveCdn> liveCdns = ServiceLoader.load(ILiveCdn.class);
            for (ILiveCdn u : liveCdns) {
                u.upload("http://www.baidu.com");
                u.play("play movie");
            }
        }
     
    }
    

    可以看到,调用成功~。

    总结

    优点:
    不需要改动源码就可以实现扩展,解耦。
    实现扩展对原来的代码几乎没有侵入性。
    只需要添加配置就可以实现扩展,符合开闭原则。

    缺点:
    只能遍历所有的实现,并全部实例化
    配置文件中只是简单的列出了所有的扩展实现,而没有给他们命名。导致在程序中很难去准确的引用它们。
    扩展如果依赖其他的扩展,做不到自动注入和装配。
    扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持。
    多个并发多线程使用 ServiceLoader 类的实例是不安全的

    相关文章

      网友评论

          本文标题:SPI

          本文链接:https://www.haomeiwen.com/subject/xjejmrtx.html