SPI implementation project pluggable use of project extra components practice

        Recently, a project needs to store file content, the customer does not use the product default object storage, and the product does not want to integrate customized code into the product, so it needs to be designed as a pluggable plug-in, and the first contact with SPI and SpringBoot Starter. The two are very similar and different. Here is a summary of the SPI implementation; the following is a complete example;

        Many blogs on the Internet have all the codes in one project, which is inconvenient to understand and use. Here, it is divided into 3 projects according to the real usage scenarios; the example requires 3 jars; the interface jar, the plug-in jar, and the business jar; the source code link at the end of the article .

The IDEA project is as follows: 

1. Write the interface jar -- for use by the other two jars

 pom coordinates

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.idto.spi</groupId>
    <artifactId>idto-spi-api</artifactId>
    <version>1.0</version>
    <description>SPI-接口层jar包</description>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>7</source>
                    <target>7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>

    </dependencies>
</project>

Define an interface class 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);
}

Compile and package idto-spi-api.jar into the local warehouse and use it later.

2. Write SPI plugin -- plugin jar

 pom coordinates, import the idto-spi-api.jar package created in step 1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.org.bjca</groupId>
    <artifactId>idto-spi-plug</artifactId>
    <version>1.0</version>
    <description>SPI-插件jar包</description>

    <dependencies>
        <!--引入定义的接口-->
        <dependency>
            <groupId>com.idto.spi</groupId>
            <artifactId>idto-spi-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>7</source>
                    <target>7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Write the implementation class of the interface Say, two implementation classes are written here

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);
    }
}

focus  

Create a new META-INF.services under resources, and then create a new file com.idto.spi.Say (full path of the interface) under services. com.idto.spi.Say writes the full description of the implementation class to be used in the file. path, multiple implementation classes are written in lines

 Compile and package idto-spi-plug.jar into the local warehouse and use it later.

Now that the SPI implementation has been completed, let's see how to use it!

 3. Write business code -- business jar

 pom coordinates, import the idto-spi-api.jar package created in step 1

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.org.bjca</groupId>
    <artifactId>idto-spi-business</artifactId>
    <version>1.0</version>
    <description>SPI-业务jar包</description>

    <dependencies>
        <!--引入定义的接口-->
        <dependency>
            <groupId>com.idto.spi</groupId>
            <artifactId>idto-spi-api</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/resource</directory>
                <includes>
                    <include>*</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <!-- 设置主类  -->
                                    <mainClass>com.idto.spi.Main</mainClass>
                                </transformer>
                            </transformers>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <!-- 打包时过滤无用的文件,不打包进jar -->
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                                <filter>
                                    <artifact>junit:junit</artifact>
                                    <includes>
                                        <include>junit/framework/**</include>
                                        <include>org/junit/**</include>
                                    </includes>
                                    <excludes>
                                        <exclude>org/junit/experimental/**</exclude>
                                        <exclude>org/junit/runners/**</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Write the calling method of SPI and load the plug-in through the ServiceLoader that comes with java; specify the directory of the plug-in in the code, preferably outside the project jar, which is convenient for plugging and unplugging. The name of the plug-in is written in the code for reference only.

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<Say> says = ServiceLoader.load(Say.class, urlClassLoader);
        for (Say say : says) {
            say.sayWithLanguage("Hello World!");
        }
        System.out.println("---end---");
    }
}

At this point, you can test directly in the code;

In order to simulate the real usage scenario, we package and compile, and copy the typed idto-spi-business-1.0.jar to a test directory for testing;

Test Scenario 1: No Plugins

 The corresponding implementation class is not found, and the print is empty

Test scenario 1: Place the plug-in according to the specified directory

Put idto-spi-plug-1.0.jar under D:\log\plugs

 Run the business class code, and the result is that the methods of the two implementation classes run successfully, as follows:

Source code address: https://gitee.com/idtolerate/idto-spi-demo

It is not easy to be original. If it is helpful to you, you are welcome to like and collect (#^.^#)

Guess you like

Origin blog.csdn.net/idto315/article/details/123065676