【曹工杂谈】说说Maven框架和插件的契约

说说Maven框架和插件的契约 前言

Maven框架就像现在公司内的各种平台方,规定一些契约,然后想办法拉动业务方,一起在这个平台上去做生态共建。Maven也是这样,其实它就是一个插件执行的框架,Maven刚开始肯定不知道会有谁去贡献插件,插件如果写得五花八门的话,那对于平台方来说,可能就是一个灾难,所以,平台方就要负责定标准,要在我平台上写插件,必须怎么怎么样。

Maven给插件就定了契约,这个契约,是通过api jar包的方式。每次发布Maven新版本,与之伴随的,都会有一个api jar包。

【曹工杂谈】说说Maven框架和插件的契约

如果有人要基于这个版本的api jar包来开发插件,就需要把这个插件引入到自己的插件工程中。然后根据api jar包中的契约接口,来实现自己的插件逻辑。

比如,maven clean插件的工程代码中,就依赖了api jar包。如下:

【曹工杂谈】说说Maven框架和插件的契约

api jar包中的契约接口长啥样呢?

public interface Mojo { ... void execute() throws MojoExecutionException, MojoFailureException; }

核心方法就是这个,只要你实现这个接口就完事了。

【曹工杂谈】说说Maven框架和插件的契约

作为框架方,怎么去调用这个插件呢?简而言之,就是:

1、找到插件的实现类jar包,然后构造一个该插件的类加载器,去加载这个jar包,然后找到对应的实现了契约接口的类,比如这里的CleanMojo

2、加载了这个CleanMojo的class之后,当然是反射生成对象,然后强制转换为契约接口,然后调用契约接口就行。比如:

Class cleanMojoClass = 插件的类加载器加载插件的jar包; Mojo cleanMojo = (Mojo)cleanMojoClass.newInstance(); cleanMojo.execute();

到此为止,我们的理论知识已经足够了,我们是不是可以show the code了?

工程实践

我们会模拟上面的过程,

建一个Maven module,用来存放插件api契约接口;

建一个Maven module,引入api,实现插件api,这样,我们的插件就算是实现好了;

接下来,把这两个工程编译一下,把jar包安装到本地仓库;

再新建一个工程,模拟Maven框架去加载插件,并执行插件。

插件api工程

直接用maven的archetype中的quickstart,新建一个module,里面很简单,就一个接口:

【曹工杂谈】说说Maven框架和插件的契约

然后执行mvn install,安装到本地仓库。

插件实现工程

在pom中,我们会引入api。

<dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-plugin-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>

代码也很简单,就一个实现类。

【曹工杂谈】说说Maven框架和插件的契约

然后执行mvn install,安装到本地仓库。

主工程,模拟框架去调用插件

主工程就是模拟我们的Maven框架,由于我们调用插件,肯定是通过api的方式,所以,pom中肯定是要引入api的。

<dependencies> <dependency> <groupId>org.example</groupId> <artifactId>my-plugin-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>

接下来,我们写了个测试类:

public static void main( String[] args ) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException { // 1.1处 URL urlForPluginApi = new URL("file:/C:\\Users\\Administrator\\.m2\\repository\\org\\example\\my-plugin-api\\1.0-SNAPSHOT\\my-plugin-api-1.0-SNAPSHOT.jar"); URL urlForPluginImpl = new URL("file:/C:\\Users\\Administrator\\.m2\\repository\\org\\example\\my-plugin-implementation\\1.0-SNAPSHOT\\my-plugin-implementation-1.0-SNAPSHOT.jar"); URL[] urls = {urlForPluginApi, urlForPluginImpl}; // 1.2 URLClassLoader urlClassLoader = new URLClassLoader(urls,ClassLoader.getSystemClassLoader()){ @Override public Class<?> loadClass(String name) throws ClassNotFoundException { try{ // 保证:寻找类时,优先查找自己的classpath,找不到,再去交给parent classloader Class<?> clazz = findClass(name); return clazz; }catch (ClassNotFoundException exception ){ return super.loadClass(name); } } }; // 1.3 Class<?> implClazzByPluginClassloader = urlClassLoader.loadClass("org.example.MyMojoImplementation"); // 1.4 MojoInterface mojoInterface = (MojoInterface) implClazzByPluginClassloader.newInstance(); // 1.5 mojoInterface.execute(); System.out.println( "Hello World!" ); }

我先大概讲解一下上述代码:

1.1处,构造了两个url,分别指向我本地仓库的两个文件,也就是api.jar和插件对应的实现的jar

1.2处,使用1.1中的url,构造了一个classloader,这个classloader的parent classloader,我们传的是,系统的AppClassloader。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzpsxd.html