Recently, there is a project that needs to store file content. Customers do not use the default object storage of the product, and the product does not want to integrate customized code into the product. Therefore, it needs to be designed as a pluggable plug-in to contact SPI and SpringBoot Starter for the first time. The two are very similar and different. Here, let's sort out the SPI implementation; The following is a complete example;
All the codes of many online blogs are kneaded in one project, which is not easy to understand and use. Here, they are divided into three projects according to the real use scenario; The example requires three jars; Interface jar, plug-in jar and business jar; There is a link to the source code at the end of the article.
IDEA works are as follows:
1. Write the interface jar -- for 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-Interface layer jar package</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 The defined interface needs to be referenced by the business layer and the implemented plug-in * @date 2022/2/22 10:40 */ public interface Say { void sayWithLanguage(String language); }
IDto SPI API Jar compilation is packaged into the local warehouse and used later.
2. Write SPI plug-in -- plug-in jar
pom coordinates, introduce the IDto SPI API set in step 1 Jar package
<?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-plug-in unit jar package</description> <dependencies> <!--Import defined interface--> <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 interface Say. Here are two implementation classes
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("Chinese speaking-->"+s); } }
Focus
Create META-INF.services under resources, and then create a new file com.inf under services idto. spi. Say (full path of interface), com idto. spi. Say writes the full path of the implementation class to be used in the file, and multiple implementation classes are written in separate lines
Add IDto SPI plug Jar compilation is packaged into the local warehouse and used later.
The SPI implementation has been completed. Let's see how to use it!
3. Writing business code -- business jar
pom coordinates, introduce the IDto SPI API set in step 1 Jar package
<?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-business jar package</description> <dependencies> <!--Import defined interface--> <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"> <!-- Set main class --> <mainClass>com.idto.spi.Main</mainClass> </transformer> </transformers> <filters> <filter> <artifact>*:*</artifact> <!-- When packing, filter useless files and do not pack them into 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 service loader provided by java; The directory of plug-ins specified in the code should be outside the project jar for easy plugging. The name of plug-ins 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 Call example * @date 2022/2/22 13:02 */ public class Main { public static void main(String[] args) throws MalformedURLException { // Get the path of the plug-in 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 the code directly;
In order to simulate the real use scenario, we package and compile the prepared idto-spi-business-1.0 Copy jar to a test directory for testing;
Test scenario 1: no plug-ins
The corresponding implementation class is not found, and the print is empty
Test scenario 1: place the plug-ins according to the specified directory
Put idto-spi-plug-1.0 under D:\log\plugs jar
Run the business class code. As a result, the methods of the two implementation classes run successfully, as follows:
Originality is not easy. If it helps you, you are welcome to like the collection (# ^. ^ #)