【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕

Maven底层容器Plexus Container的前世今生,一代芳华终落幕 前言 说实话,我非常地纠结,大家平时只是用Maven,对于内部的实现其实也不关心,我现在非要拉着大家给大家讲。这就有个问题,Maven的内部,还是相对没那么简单的,也算是个不小的工程了。
核心功能,大家是清楚的,内部的执行流程,大家也大概猜的出来:

  1. 解析命令行参数
  2. 准备各种上下文,简单的mvn clean就涉及到当前项目的元数据pom.xml、settings.xml(主要是本地、远程仓库相关);
  3. 根据mvn clean或者mvn compile,找到对应的生命周期(大家应该都知道maven的三个lifecycle吧);然后看看要执行生命周期中的哪些阶段,顺序是啥(这个和打包方式也有关,jar/war时,打包组件就不同);
  4. 顺序执行生命周期中的每个阶段的时候,去找到对应的绑定的插件,然后执行插件(执行插件又包括:根据插件坐标,去本地仓库/远程仓库找对应的artifact,以及解析artifact中的插件元数据,元数据中会告诉你,支持传哪些参数,参数类型是啥)
  5. 执行完成后,返回结果。
这么一个不小的工程,想必,还是会有很多对象互相依赖的,在没有依赖注入前,都是靠new,或者是工厂来缓解;我查了下历史资料,maven的开发者在一篇文章中(https://blog.sonatype.com/201...),提到:
We knew we needed some sort of component framework, some standard mechanism to instantiate plugins and configure them based on a set of configuration points
大概意思,他们也发现他们需要一个组件框架,一种标准化能够实例化组件的机制,能够基于一组配置来配置这些组件。
说明,早期的Maven开发者们,已经意识到了自己可能需要一个类似容器的东西,那,为啥没有选用Spring呢?
下边,让我们来层层揭开历史的面纱。
Maven初起步 查阅了Maven官网,发现Maven的第一个版本,竟然早在2002年。(http://jakarta.apache.org/sit...)。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

2003年,成为Apache顶级项目,2004年,发布1.0版本。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

另外一边,我们熟知的,无人不知无人不晓的Spring呢,第一个版本是什么时候呢?
The first version was written by Rod Johnson), who released the framework with the publication of his book Expert One-on-One J2EE Design and Development in October 2002.
这里说,spring的第一个版本同样发布于2002年,是跟随着Rod Johnson的书《Expert One-on-One J2EE Design and Development 》一起发布的。也是在03年,使用Apache 2.0 License,发布了一个版本;04年3月,发布了一个生产用的版本。
所以,我们就可以理解,Maven的开发者在那篇2010年的文章里写的:
When we started the Maven project, dependency injection was still developing. Spring was just starting out and the Avalon project at Apache was really the only IoC framework around
【【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕】简单说,就是,当开始搞Maven的时候,依赖注入还在发展当中。Spring刚起步,Avalon项目,也仅仅只是一个ioc框架。
既然外部不成熟,他们的重心也不在这些依赖注入框架上面,所以他们就基于自己的需求,自己搞了一个适合Maven的,它就叫:Plexus。
Maven早期:做自己的IOC容器 Plexus项目
Plexus: 发音(?pleks?s),a network of nerves or vessels in the body.

Plexus,中文意思,可能是神经网络或者血管网络,就因为血管是网状的,像他么互联网一样,所以被拿来当一个框架名了吗,maybe。
这个项目(官网:https://codehaus-plexus.githu...),定位是做容器。官网不知道为啥,这会打不开,但是我发现一个记录互联网历史的网站:https://web.archive.org/web/2...。
Plexus项目,基于其中的Plexus Container子项目,应用程序可以使用基于组件的编程方式,构建模块化的、可复用的组件。Plexus类似其他的IOC框架,如Spring,但它还额外提供了很多特性,如:组件生命周期管理、组件实例化策略、嵌套容器、组件配置、自动注入、组件依赖、各种依赖注入方式(如构造器注入、setter注入、字段注入)。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

总的来说,我个人感觉,这些特性,Spring好像也有啊,哈哈。
Plexus 下组件 Plexus这么一个项目,当然不止容器,大概有如下几个:
  • Plexus Classworlds,类加载器框架,Maven至今还在用,个人感觉也挺不错,推荐学习学习;
  • Plexus Container,IOC容器,Maven 1.x/2.x在用,3.0版本后,Maven自身也没有再使用了
  • Plexus Components
    Maven的工作就是和各种文件、目录打交道,这期间,会沉淀出来很多公用组件:
    1. IO相关的,Plexus IO Components,它的maven坐标:
    org.codehaus.plexus plexus-io 3.2.0

    1. 归档相关的,Plexus Archiver Component,maven坐标:
      org.codehaus.plexus plexus-archiver 4.2.5

    2. cli相关,Plexus CLI
    3. 编译相关,Plexus Compiler
    4. Digest/Hashcode相关,Plexus Digest / Hashcode Components
    5. 国际化相关,i18n
    还有些其他的,我懒得列举了,大家自己看吧,https://web.archive.org/web/2...
  • Plexus Maven Plugin,用来支持Maven插件
  • Plexus Utils,工具类,至今仍在用
Plexus组件的现状 打开我本机的maven安装目录的lib,发现plexus相关的,仅剩少数几个了,如,下图的几个工具:
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

还有下图的启动类: 【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

当初说好的IOC容器,结果Maven怎么自己也不用了呢?我们来看看这个容器相关的组件吧。
容器相关的,一共4个maven组件。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

这里面,plexus-component-annotations我们刚看到,还在用,他是干嘛的呢,就是类似于Spring里面的注解,比如@Service/@Controller这种。
而plexus-component-metadata,是一个maven插件,用来生成组件的xml,有点像我们的spring的xml时代,这个工程呢,就可以分析我们代码,帮我们生成spring的bean.xml这种,就不需要手动配置依赖了。
这里面,真正的IOC容器实现,就是:plexus-container-default。
该组件,可以说是Maven的结发妻子,陪伴了Maven的青年时期,我们看看这个组件是什么时候第一次登场的。
下边是它1.0版本的坐标:
plexus plexus-container-default 1.0-alpha-1

时间是2005年。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

而maven什么时候开始使用该容器呢,我没有查到maven 1.x版本的pom依赖,但是在2.0.alpha版本,已经看到了该容器的身影:
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

此时,是2006年。
仅仅几年后,在maven 3.0的版本中,已经不再有plexus ioc容器的身影,却来了一个不速之客。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

在开始说不速之客之前,我们还是要问问,plexus ioc容器,为啥就不行了呢?对这个历史感兴趣的,可以直接看:
https://blog.sonatype.com/201...
为什么呢?因为时代变了,此时,Spring已经开始成为事实上的IOC容器标准,不过,虽然Spring在应用开发领域,所向披靡,但是在各种框架中,框架开发者们还是觉得Spring太重了,一下就要引入好几个jar包,实在是过于臃肿。因此,google 在2007年的时候,就推出了一个轻量级的依赖注入框架,叫google guice。
此时,经过多年的迭代,在2010年前后,guice已经比较成熟了,在google内部也而得到了广泛应用,且依赖注入这个领域,也在持续不断地发展中,比如java官方定义了相关的标准api。
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

而此时,Maven的开发者们已经难以同时维护Plexus IOC容器(比如适配java官方新出标准,和周边Spring兼容等等各类工作),因此,Maven决定,为了节省精力,Maven将不再基于Plexus IOC容器,而是使用Guice,以后就只管用了,而guice的维护升级,自然有Guice的开源团队去跟进。
说了那么多,为了纪念Plexus Container的落幕,我们还是来看看,这个IOC组件到底怎么用的吧?
Plexus IOC容器初使用 例子也是来自于官网,我根据文档,整理成了一个maven module。大家可以拉代码下来。
https://gitee.com/ckl111/mave...
1.像所有的IOC容器一样,定义一个接口和实现类
public interface Cheese { /** The Plexus role identifier. */ String ROLE = Cheese.class.getName(); /** * Slices the cheese for apportioning onto crackers. * @param slices the number of slices */ void slice( int slices ); /** * Get the description of the aroma of the cheese. * @return the aroma */ String getAroma(); }

public class ParmesanCheese implements Cheese { public void slice( int slices ) { throw new UnsupportedOperationException( "No can do" ); }public String getAroma() { return "strong"; } }

就像spring的xml时代一样,定义组件的依赖关系 【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
文章图片

注意一下,这里的组件配置中,有三个元素:
  • role,此处放:接口名称
  • role-hint,此处放:实现类的qualifier,类似spring中,一个接口多个实现类,我们就会给这多个实现类,定义一个显示的名字,@Qualifier
  • implementation,实现类的类名。
ok,这就定义好了一个组件。
我们开始测试。
从容器中获取组件
public class App { public static void main(String args[]) throws Exception { // 1定义一个容器,容器会去加载classpath下的META-INF/Plexus/component.xml中的组件 PlexusContainer container= new DefaultPlexusContainer(); // 2 获取组件,完成依赖注入等工作 Cheese cheese = (Cheese) container.lookup( Cheese.ROLE, "parmesan" ); // 3 使用组件 System.out.println( "Parmesan is " + cheese.getAroma() ); // 4 销毁容器 container.dispose(); } }

其他用法 如果这个组件,依赖其他组件,怎么办呢,怎么注入呢?
我在maven源码工程里看到这样的组件配置,想必,就是像如下这样配置。
org.apache.maven.profiles.activation.ProfileActivator faulty org.ext.App org.apache.maven.artifact.ArtifactResolver artifactResolver

循环依赖怎么办呢?放心,人家也是可以解决的,这里就不截图了。
总结 一个组件,写出来,竟然感觉就像是也有感情一样,也是有点意思。不过不管怎么说,Plexus Container在陪伴Maven度过了整个2.x版本后,终将落下帷幕。
接下来,是Guice的时代,而现在,十多年后的2021年,Guice依然稳定地支撑着Maven。Guice足够优秀,在此之前,我竟然几乎没什么了解,Guice在哪些地方有应用呢,简单列举几个:
  • google内部
  • scalatest
  • TestNG
  • Caffeine Cache
  • Spring Security Config
  • elastic search
  • jenkins
以及一些其他的我不太熟悉的技术,大家可以查看:
https://mvnrepository.com/art...
本文由博客一文多发平台 OpenWrite 发布!

    推荐阅读