写代码我们都知道要抽象,要封装变化,要实现开闭原则,比如对于很多相似的功能,我们可以将通用的功能抽象出来,然后把变化的不同的地方提取出去,比如模版模式、策略模式等都是实现类似的效果
比如对于策略模式,我们通常是定义一个接口,然后有不同的实现,这种是可以的,但是如果通用流程中要扩展的点较多的话,这些不同的实现也需要管理,可以把他们合并到一个单独的包中,再进一步,我们甚至可以将包单独提取出来,支持运行时加载包实现新增功能的支持
JDK对此功能的支持就是 SPI,但是它的限制较多,也不够灵活,比如dubbo就是自己定义了一套SPI的实现,这次我们来看另一个实现,pf4j 提供一套在基本框架中定义扩展点接口,然后通过不同的插件来实现扩展点的功能,来支持对新增开放对修改关闭
这次我们就来学习一下它的使用
使用
比如我们有一套通用的流程,假设是下单流程,不同的业务线等对于下单都有一些特殊点,但是它们的基本流程是相似的,这时候我们就可以先定义好通用的流程,不同的地方预留出扩展点接口,使用 pf4j 的流程如下
- 先定义好扩展点接口(需要定义单独的包,因为基本应用和各个扩展点的包都依赖它)
 
- 定义单独的插件包,其中实现扩展点接口的功能
 
- 在应用中编写基本流程和扩展点的发现使用功能
 
这次我们就参考 pf4j 提供的例子来看一下
1. 定义扩展点接口
pom.xml首先声明依赖
1 2 3 4 5 6 7
   | <dependency>     <groupId>org.pf4j</groupId>     <artifactId>pf4j</artifactId>     <version>3.6.0</version>          <scope>provided</scope> </dependency>
   | 
 
之后即可声明各个扩展点接口
1 2 3 4 5 6 7
   | 
 
 
  public interface Notice extends ExtensionPoint {     boolean notice(List<Long> userIds); }
 
  | 
 
2. 各个插件实现
pom.xml修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
   | <properties>     <maven.compiler.source>8</maven.compiler.source>     <maven.compiler.target>8</maven.compiler.target>
           <plugin.id>email-plugin</plugin.id>     <plugin.version>0.0.1</plugin.version>          <plugin.class />     <plugin.provider>user1</plugin.provider>     <plugin.dependencies/> </properties>
  <dependencies>          <dependency>         <groupId>org.pf4j</groupId>         <artifactId>pf4j</artifactId>         <version>3.6.0</version>         <scope>provided</scope>     </dependency>     <dependency>         <groupId>com.zavier.demo</groupId>         <artifactId>extension-api</artifactId>         <version>1.0.0-SNAPSHOT</version>         <scope>provided</scope>     </dependency>
           <dependency>         <groupId>com.google.guava</groupId>         <artifactId>guava</artifactId>         <version>30.1.1-jre</version>     </dependency> </dependencies>
  <build>     <plugins>         <plugin>                          <groupId>org.apache.maven.plugins</groupId>             <artifactId>maven-assembly-plugin</artifactId>             <version>3.1.0</version>             <configuration>                 <descriptorRefs>                     <descriptorRef>jar-with-dependencies</descriptorRef>                 </descriptorRefs>                 <attach>false</attach>                 <archive>                     <manifest>                         <addDefaultImplementationEntries>true</addDefaultImplementationEntries>                     </manifest>                     <manifestEntries>                         <Plugin-Id>${plugin.id}</Plugin-Id>                         <Plugin-Version>${plugin.version}</Plugin-Version>                         <Plugin-Provider>${plugin.provider}</Plugin-Provider>                         <Plugin-Class>${plugin.class}</Plugin-Class>                         <Plugin-Dependencies>${plugin.dependencies}</Plugin-Dependencies>                     </manifestEntries>                 </archive>             </configuration>             <executions>                 <execution>                     <id>make-assembly</id>                     <phase>package</phase>                     <goals>                         <goal>single</goal>                     </goals>                 </execution>             </executions>         </plugin>     </plugins> </build>
   | 
 
功能实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | 
 
  @Extension public class EmailNotice implements Notice {
      @Override     public boolean notice(List<Long> userIds) {                  final ArrayList<Object> objects = Lists.newArrayList();         System.out.println("email notice");         return true;     } }
 
  | 
 
如果还有其他插件,也是类似的实现
3.插件使用
将之前打包的插件包放到一个路径包下,之后新建一个应用模版,就可以获取插件中的扩展点并使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | public static void main(String[] args) {          PluginManager pluginManager = new DefaultPluginManager(Paths.get("/u/plugins"));     pluginManager.loadPlugins();     pluginManager.startPlugins();
      List<Long> list = new ArrayList<>();     final List<Notice> extensions = pluginManager.getExtensions(Notice.class);     extensions.forEach(e -> e.notice(list));               extensions = pluginManager.getExtensions(Notice.class, "email-plugin");     extensions.forEach(e -> e.notice(list));
      pluginManager.stopPlugins();     pluginManager.unloadPlugins(); }
  | 
 
例子代码地址:https://github.com/zavier/pf4j-demo