SPI实现项目可插拔式使用项目额外组件实践

        最近有个项目需要存储文件内容,客户又不使用产品默认对象存储,产品又不想将定制的代码融入到产品中,因此需要设计成可插拔的插件,初次接触到SPI 和 SpringBoot Starter。两者很像,又有所区别,这里梳理一下SPI实现;下面是一个完整的示例;

        网上很多博客所有代码都揉在一个工程中,不便于理解和使用,这里按真正的使用场景分为了3个工程;示例需要3个jar ; 接口jar 、插件jar、 业务jar;文章最后有源码链接。

SPI实现项目可插拔式使用项目额外组件实践_第1张图片

IDEA工程如下: 

SPI实现项目可插拔式使用项目额外组件实践_第2张图片

1.编写接口jar--供另外两个jar使用

 pom坐标



    4.0.0

    com.idto.spi
    idto-spi-api
    1.0
    SPI-接口层jar包
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    7
                    7
                
            
        
    

    

    

定义一个接口类Say

package com.idto.spi;

/**
 * @author idto
 * @title: Say
 * @projectName
 * @description: SPI定义的接口 需要业务层和实现的插件引用
 * @date 2022/2/22 10:40
 */
public interface Say {

    void sayWithLanguage(String language);
}

将idto-spi-api.jar编译打包到本地仓库中,稍后使用。

2.编写SPI插件--插件jar

 pom坐标,引入第1步打好的idto-spi-api.jar包



    4.0.0

    cn.org.bjca
    idto-spi-plug
    1.0
    SPI-插件jar包

    
        
        
            com.idto.spi
            idto-spi-api
            1.0
        
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    7
                    7
                    UTF-8
                
            
        
    

编写接口Say的实现类,这里编写了两个实现类

package com.idto.spi.impl;

import com.idto.spi.Say;


public class America implements Say {

    @Override
    public void sayWithLanguage(String s) {
        System.out.println("Speak English -->"+s);
    }
}


package com.idto.spi.impl;

import com.idto.spi.Say;


public class China implements Say {
    @Override
    public void sayWithLanguage(String s) {
        System.out.println("中文说-->"+s);
    }
}

划重点  

在resources下新建META-INF.services ,然后在services下新建文件com.idto.spi.Say(接口的全路径),com.idto.spi.Say在文件中写入要用到的实现类的全路径,多个实现类分行写入

SPI实现项目可插拔式使用项目额外组件实践_第3张图片

 将idto-spi-plug.jar编译打包到本地仓库中,稍后使用。

到这不SPI实现已经完成,下面我们看看怎么使用吧!

 3.编写业务代码--业务jar

 pom坐标,引入第1步打好的idto-spi-api.jar包



    4.0.0

    cn.org.bjca
    idto-spi-business
    1.0
    SPI-业务jar包

    
        
        
            com.idto.spi
            idto-spi-api
            1.0
        
    

    
        
            
                src/main/resource
                
                    *
                
            
        

        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    8
                    8
                
            
            
                org.apache.maven.plugins
                maven-shade-plugin
                3.1.1
                
                    
                        package
                        
                            shade
                        
                        
                            
                                
                                    
                                    com.idto.spi.Main
                                
                            
                            
                                
                                    *:*
                                    
                                    
                                        META-INF/*.SF
                                        META-INF/*.DSA
                                        META-INF/*.RSA
                                    
                                
                                
                                    junit:junit
                                    
                                        junit/framework/**
                                        org/junit/**
                                    
                                    
                                        org/junit/experimental/**
                                        org/junit/runners/**
                                    
                                
                            
                        
                    
                
            
        
    

编写SPI的调用方法,通过java自带的ServiceLoader加载插件;代码中指定插件的目录,最好在项目jar外,方便插拔,代码中写死了插件的名称,仅供参考

package com.idto.spi;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ServiceLoader;


/**
 * @author idto
 * @title: Main
 * @projectName idto-spi-business
 * @description:  SPI调用例子
 * @date 2022/2/22 13:02
 */
public class Main {
    public static void main(String[] args) throws MalformedURLException {
        // 获取插件的路径
        String projectPath = System.getProperty("user.dir");
        Path path = Paths.get(projectPath);
        String plugPath = path.toString() + File.separator + "plugs";
        String location = plugPath + File.separator + "idto-spi-plug-1.0.jar";
        System.out.println("plug Path is -->" + location);
        System.out.println( );
        System.out.println( );

        System.out.println("---start---");
        URL url = new File(location).toURI().toURL();
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader());
        ServiceLoader says = ServiceLoader.load(Say.class, urlClassLoader);
        for (Say say : says) {
            say.sayWithLanguage("Hello World!");
        }
        System.out.println("---end---");
    }
}

到这步,可以直接在代码进行测试了;

为了模拟真是使用场景,我们打包编译,将打好的idto-spi-business-1.0.jar 复制到一个测试目录下进行测试;

测试场景一:不放插件

SPI实现项目可插拔式使用项目额外组件实践_第4张图片

 没有找到对应的实现类,打印为空

测试场景一:按照指定目录安放插件

在D:\log\plugs下放入idto-spi-plug-1.0.jar

 运行业务类代码,结果两个实现类的方法成功运行,如下:

SPI实现项目可插拔式使用项目额外组件实践_第5张图片

源代码地址:https://gitee.com/idtolerate/idto-spi-demo

原创不易,如对您有所帮助,欢迎您点赞 收藏(#^.^#)

你可能感兴趣的:(java,后端,spi)