<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Heck's  Blog]]></title> 
<link>https://www.heckjj.com/index.php</link> 
<description><![CDATA[一瞬间的决定，往往可以改变很多，事实上，让自己成功的往往不是知识，是精神！ 如果你总是为自己找借口，那只好让成功推迟。执行力，今天！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Heck's  Blog]]></copyright>
<item>
<link>https://www.heckjj.com/post//</link>
<title><![CDATA[使用PF4J动态加载java插件]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[编程杂谈]]></category>
<pubDate>Thu, 24 Nov 2022 14:00:34 +0000</pubDate> 
<guid>https://www.heckjj.com/post//</guid> 
<description>
<![CDATA[ 
	PF4J是一个Java轻量级的插件框架，可以实现动态加载，执行，卸载外部插件(支持jar以及zip)，具体可以看官网：https://pf4j.org/。<br/><br/>本文例子基于Github地址：https://github.com/pf4j/pf4j<br/><br/>&lt;dependency&gt;<br/>&nbsp;&nbsp;&lt;groupId&gt;org.pf4j&lt;/groupId&gt;<br/>&nbsp;&nbsp;&lt;artifactId&gt;pf4j&lt;/artifactId&gt;<br/>&nbsp;&nbsp;&lt;version&gt;3.6.0&lt;/version&gt;<br/>&lt;/dependency&gt;<br/>插件项目会涉及到3个工程：工程结构<br/>plugin-api：定义可扩展接口<br/>plugins：插件项目，可以包含多个插件，需要实现plugin-api中定义的接口<br/>plugin-app：主程序，需要依赖plugin-api，加载并执行plugins<br/>定义可扩展接口(plugin-api)<br/>简单定义一个接口，需继承ExtensionPoint：<br/><br/>package plugin.api;<br/><br/>import org.pf4j.ExtensionPoint;<br/><br/>public interface Greeting extends ExtensionPoint &#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;String getGreeting();<br/>&#125;<br/>实现插件(plugins)<br/>插件需要实现plugin-api定义的接口，并且使用@Extension标记：<br/>package plugins;<br/><br/>import org.pf4j.Extension;<br/>import plugin.api.Greeting;<br/><br/>@Extension<br/>public class WelcomeGreeting implements Greeting &#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public String getGreeting() &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return &quot;Welcome&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/>插件打包(plugins)<br/>插件打包时，需要往MANIFEST.MF写入插件信息，此处使用maven插件(打包命令为package)：<br/>&lt;plugin&gt;<br/>&nbsp;&nbsp;&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br/>&nbsp;&nbsp;&lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;<br/>&nbsp;&nbsp;&lt;version&gt;2.3.1&lt;/version&gt;<br/>&nbsp;&nbsp;&lt;configuration&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;archive&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;manifestEntries&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Plugin-Id&gt;welcome-plugin&lt;/Plugin-Id&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Plugin-Version&gt;0.0.1&lt;/Plugin-Version&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/manifestEntries&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/archive&gt;<br/>&nbsp;&nbsp;&lt;/configuration&gt;<br/>&lt;/plugin&gt;<br/> <br/><br/>根据Github上介绍，MANIFEST.MF中Plugin-Id以及Plugin-Version是必须信息：<br/><br/>In above manifest I described a plugin with id welcome-plugin (mandatory attribute), with class org.pf4j.demo.welcome.WelcomePlugin (optional attribute), with version 0.0.1 (mandatory attribute) and with dependencies to plugins x, y, z (optional attribute).<br/><br/>此处定义插件ID为welcome-plugin，版本为0.0.1<br/><br/>加载执行插件(plugin-app)<br/>package plugin.app;<br/><br/>import java.nio.file.Paths;<br/>import java.util.List;<br/><br/>import org.pf4j.JarPluginManager;<br/>import org.pf4j.PluginManager;<br/><br/>import plugin.api.Greeting;<br/><br/>public class Main &#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public static void main(String[] args) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// jar插件管理器<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PluginManager pluginManager = new JarPluginManager();<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 加载指定路径插件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pluginManager.loadPlugin(Paths.get(&quot;plugins-0.0.1-SNAPSHOT.jar&quot;));<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 启动指定插件(也可以加载所有插件)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pluginManager.startPlugin(&quot;welcome-plugin&quot;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 执行插件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Greeting&gt; greetings = pluginManager.getExtensions(Greeting.class);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (Greeting greeting : greetings) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;&gt;&gt;&gt; &quot; + greeting.getGreeting());<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 停止并卸载指定插件<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pluginManager.stopPlugin(&quot;welcome-plugin&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pluginManager.unloadPlugin(&quot;welcome-plugin&quot;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/><br/><br/>运行输出：<br/><br/>&gt;&gt;&gt; Welcome<br/>其他<br/>插件周期<br/>如果对插件生命周期(如加载，执行，停止等)有兴趣的话，可以实现插件类继承Plugin：<br/><br/>package plugins;<br/><br/>import org.pf4j.Plugin;<br/>import org.pf4j.PluginWrapper;<br/><br/>public class WelcomePlugin extends Plugin &#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;public WelcomePlugin(PluginWrapper wrapper) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super(wrapper);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;@Override<br/>&nbsp;&nbsp;&nbsp;&nbsp;public void start() &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;WelcomePlugin.start()&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;@Override<br/>&nbsp;&nbsp;&nbsp;&nbsp;public void stop() &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;WelcomePlugin.stop()&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;@Override<br/>&nbsp;&nbsp;&nbsp;&nbsp;public void delete() &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(&quot;WelcomePlugin.delete()&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/>同时往MANIFEST.MF写入插件信息：<br/><br/>&lt;plugin&gt;<br/>&nbsp;&nbsp;&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br/>&nbsp;&nbsp;&lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;<br/>&nbsp;&nbsp;&lt;version&gt;2.3.1&lt;/version&gt;<br/>&nbsp;&nbsp;&lt;configuration&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;archive&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;manifestEntries&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Plugin-Id&gt;welcome-plugin&lt;/Plugin-Id&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Plugin-Version&gt;0.0.1&lt;/Plugin-Version&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;!-- 新增 --&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;Plugin-Class&gt;plugins.WelcomePlugin&lt;/Plugin-Class&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/manifestEntries&gt;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/archive&gt;<br/>&nbsp;&nbsp;&lt;/configuration&gt;<br/>&lt;/plugin&gt;<br/>打包后运行输出：<br/><br/>WelcomePlugin.start()<br/>&gt;&gt;&gt; Welcome<br/>WelcomePlugin.stop()<br/>如果对运行流程感兴趣，或者调试，可以将日志级别设为debug日志<br/> log4j.properties示例：<br/><br/>log4j.rootLogger = debug,stdout,log<br/><br/>log4j.appender.stdout = org.apache.log4j.ConsoleAppender<br/>log4j.appender.stdout.layout = org.apache.log4j.PatternLayout<br/>log4j.appender.stdout.layout.ConversionPattern = %d [%-5p] %l %r ms: %m%n<br/><br/>log4j.appender.log = org.apache.log4j.DailyRollingFileAppender<br/>log4j.appender.log.DatePattern = _yyyy-MM-dd<br/>log4j.appender.log.File = logs/debug.log<br/>log4j.appender.log.Encoding = UTF-8<br/>log4j.appender.log.layout = org.apache.log4j.PatternLayout<br/>log4j.appender.log.layout.ConversionPattern = %d [%-5p] (%c.%t): %m%n
]]>
</description>
</item><item>
<link>https://www.heckjj.com/post//#blogcomment</link>
<title><![CDATA[[评论] 使用PF4J动态加载java插件]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://www.heckjj.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>