Java SPI 插件化开发

目录

1.什么是SPI

2.为什么要使用SPI思想

3.SPI 调用机制

4.SPI 具体应用案例

4.1 JDK

4.2 DriverManager

4.3 Spring 自定义标签


1.什么是SPI

        SPI:Service Provider Interface,是Java提供的一套被第三方实现或者扩展的接口,用来启用框架扩展和替换组件。

2.为什么要使用SPI思想

         为了降低耦合性、提高系统可扩展性。一般来说对于未知的实现或者对扩展开放的系统,通常会把一些逻辑抽成各个模块,这些模块往往有很多不同的实现方案,比如对接不同第三方日志系统、对接不同数据库驱动、编程软件需要加载一些用户开发的插件等。总结来说,SPI思想适用于调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略。

3.SPI 调用机制

Java SPI 插件化开发_第1张图片

4.SPI 具体应用案例

4.1 JDK

Java SPI 插件化开发_第2张图片        

非常简单的四个类

Leads:线索接口

public interface Leads {
    /**
     * 接收线索分发器下发的线索
     * @return 线索名称
     */
    String receiveLeads();
}

LeadsManager:线索管理类

public class LeadsManager {

    public static synchronized void initLeadsManager() {
        loadInitialParsers();
    }

    private static void loadInitialParsers() {
        System.out.println("LeadsManager initialized");
        ServiceLoader loadedParsers = ServiceLoader.load(Leads.class);

        for (Leads lead : loadedParsers) {
            System.out.println(lead.receiveLeads());
        }
    }
}

BmwLeads:宝马线索实现类

public class BmwLeads implements Leads {

    @Override
    public String receiveLeads() {
        return "宝马线索下发成功";
    }
}

BenzLeads:奔驰线索实现类

public class BenzLeads implements Leads {

    @Override
    public String receiveLeads() {
        return "奔驰线索下发成功";
    }
}

 APP:测试类

public class App {
    public static void main(String[] args) {
        LeadsManager.initLeadsManager();
    }
}

另外还有两个重要的配置文件: 

Java SPI 插件化开发_第3张图片

Java SPI 插件化开发_第4张图片

注: 1.需要在resources目录下新建META-INF/services目录

        2.在resources/META-INF/services新建一个文件,命名与需扩展接口的全限定名一致

        3.在这个文件中写入接口的实现类的全限定名

        4.接口实现类所在的jar包放在主程序的classpath中

        5.主程序通过java.util.ServiceLoder动态装载实现模块,它通过扫描META-INF/services目录下的配置文件找到实现类的全限定名,把类加载到JVM中

        6.SPI的实现类必须携带一个不带参数的构造方法

Java SPI 插件化开发_第5张图片

4.2 DriverManager

       在加载MySql驱动的时,我们都调用了这样一行函数Class.forName("com.mysql.jdbc.Driver"),但为什么调用这样一行代码就可以加载mysql驱动了呢?其实这里也运用了SPI的思想。SDK提供了这样一个接口:java.sql.Driver

Java SPI 插件化开发_第6张图片

        而不同的数据库厂商又对这个接口进行了不同的实现,比如mysql的Driver:

Java SPI 插件化开发_第7张图片

        继续跟进JDK提供的DriverManager类:

Java SPI 插件化开发_第8张图片

Java SPI 插件化开发_第9张图片

         见到了我们熟悉的代码ServiceLoader.load(XXX.class);同时在loadInitialDrivers()方法中也有 Class.forName()。

Java SPI 插件化开发_第10张图片

         最后去看下mysql的驱动包是否满足java SPI加载条件:

Java SPI 插件化开发_第11张图片

4.3 Spring 自定义标签

        扩展Spring自定义标签配置需要以下几个步骤

  1. 创建需要扩展的组件
  2. 定义XSD文件描述组件内容
  3. 创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义
  4. 创建Handler文件,扩展字NamespaceHandlerSupport,目的是将组件注册到Spring容器
  5. 编写Spring.handlers和Spring.schemas文件

        Spring为我们定义好了创建标签的流程,而无需了解我们具体的实现,只需要我们通过Spring提供的加载方式把插件加载进来,体现了spi的思想。

你可能感兴趣的:(字斟句酌业务代码,java,SPI)