【曹工杂谈】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/2010/01/from-plexus-to-guice-1-why-guice/),提到:

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/site/news/news-2002.html)。

2003年,成为Apache顶级项目,2004年,发布1.0版本。

另外一边,我们熟知的,无人不知无人不晓的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的时候,依赖注入还在发展当中。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.github.io),定位是做容器。官网不知道为啥,这会打不开,但是我发现一个记录互联网历史的网站:https://web.archive.org/web/20150323083530/http://plexus.codehaus.org/index.html

Plexus项目,基于其中的Plexus Container子项目,应用程序可以使用基于组件的编程方式,构建模块化的、可复用的组件。Plexus类似其他的IOC框架,如Spring,但它还额外提供了很多特性,如:组件生命周期管理、组件实例化策略、嵌套容器、组件配置、自动注入、组件依赖、各种依赖注入方式(如构造器注入、setter注入、字段注入)。

总的来说,我个人感觉,这些特性,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坐标:
    <!-- https://mvnrepository.com/artifact/org.codehaus.plexus/plexus-io -->
    <dependency>
        <groupId>org.codehaus.plexus</groupId>
        <artifactId>plexus-io</artifactId>
        <version>3.2.0</version>
    </dependency>
    
    
    1. 归档相关的,Plexus Archiver Component,maven坐标:

      <!-- https://mvnrepository.com/artifact/org.codehaus.plexus/plexus-archiver -->
      <dependency>
          <groupId>org.codehaus.plexus</groupId>
          <artifactId>plexus-archiver</artifactId>
          <version>4.2.5</version>
      </dependency>
      
      
    2. cli相关,Plexus CLI

    3. 编译相关,Plexus Compiler

    4. Digest/Hashcode相关,Plexus Digest / Hashcode Components

    5. 国际化相关,i18n

    还有些其他的,我懒得列举了,大家自己看吧,https://web.archive.org/web/20150225072024/http://plexus.codehaus.org/plexus-components/

  • Plexus Maven Plugin,用来支持Maven插件

  • Plexus Utils,工具类,至今仍在用

Plexus组件的现状

打开我本机的maven安装目录的lib,发现plexus相关的,仅剩少数几个了,如,下图的几个工具:

还有下图的启动类:

当初说好的IOC容器,结果Maven怎么自己也不用了呢?我们来看看这个容器相关的组件吧。

容器相关的,一共4个maven组件。

这里面,plexus-component-annotations我们刚看到,还在用,他是干嘛的呢,就是类似于Spring里面的注解,比如@Service/@Controller这种。

而plexus-component-metadata,是一个maven插件,用来生成组件的xml,有点像我们的spring的xml时代,这个工程呢,就可以分析我们代码,帮我们生成spring的bean.xml这种,就不需要手动配置依赖了。

这里面,真正的IOC容器实现,就是:plexus-container-default。

该组件,可以说是Maven的结发妻子,陪伴了Maven的青年时期,我们看看这个组件是什么时候第一次登场的。

下边是它1.0版本的坐标:

<!-- https://mvnrepository.com/artifact/plexus/plexus-container-default -->
<dependency>
    <groupId>plexus</groupId>
    <artifactId>plexus-container-default</artifactId>
    <version>1.0-alpha-1</version>
</dependency>

时间是2005年。

而maven什么时候开始使用该容器呢,我没有查到maven 1.x版本的pom依赖,但是在2.0.alpha版本,已经看到了该容器的身影:

此时,是2006年。

仅仅几年后,在maven 3.0的版本中,已经不再有plexus ioc容器的身影,却来了一个不速之客。

在开始说不速之客之前,我们还是要问问,plexus ioc容器,为啥就不行了呢?对这个历史感兴趣的,可以直接看:

https://blog.sonatype.com/2010/01/from-plexus-to-guice-1-why-guice/

为什么呢?因为时代变了,此时,Spring已经开始成为事实上的IOC容器标准,不过,虽然Spring在应用开发领域,所向披靡,但是在各种框架中,框架开发者们还是觉得Spring太重了,一下就要引入好几个jar包,实在是过于臃肿。因此,google 在2007年的时候,就推出了一个轻量级的依赖注入框架,叫google guice。

此时,经过多年的迭代,在2010年前后,guice已经比较成熟了,在google内部也而得到了广泛应用,且依赖注入这个领域,也在持续不断地发展中,比如java官方定义了相关的标准api。

而此时,Maven的开发者们已经难以同时维护Plexus IOC容器(比如适配java官方新出标准,和周边Spring兼容等等各类工作),因此,Maven决定,为了节省精力,Maven将不再基于Plexus IOC容器,而是使用Guice,以后就只管用了,而guice的维护升级,自然有Guice的开源团队去跟进。

说了那么多,为了纪念Plexus Container的落幕,我们还是来看看,这个IOC组件到底怎么用的吧?

Plexus IOC容器初使用

例子也是来自于官网,我根据文档,整理成了一个maven module。大家可以拉代码下来。

https://gitee.com/ckl111/maven-3.8.1-source-learn/tree/master/my-test-modules/plexus-ioc-container-test

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时代一样,定义组件的依赖关系

注意一下,这里的组件配置中,有三个元素:

  • 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源码工程里看到这样的组件配置,想必,就是像如下这样配置。

<?xml version="1.0"?>
<component-set>
  <components>
    <component>
      <role>org.apache.maven.profiles.activation.ProfileActivator</role>
      <role-hint>faulty</role-hint>
      <implementation>org.ext.App</implementation>
      <requirements>
        <requirement>
          <role>org.apache.maven.artifact.ArtifactResolver</role>
          <field-name>artifactResolver</field-name>
        </requirement>
      </requirements>
    </component>
  </components>
</component-set>

循环依赖怎么办呢?放心,人家也是可以解决的,这里就不截图了。

总结

一个组件,写出来,竟然感觉就像是也有感情一样,也是有点意思。不过不管怎么说,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/artifact/com.google.inject/guice/usages

本文由博客一文多发平台 OpenWrite 发布!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 本文翻译源于Apache Maven Project 官网 控制哪些jar包应该包含在项目jar中,哪些不包含 [...
    coderrrrrrrrr阅读 3,002评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 理论及实例介绍 1、Maven理论: Maven是apache下的开源项目,Maven主要服务于基于Java平台的...
    程序员日常填坑阅读 565评论 0 3
  • Spring 技术笔记Day 1 预热知识一、 基本术语Blob类型,二进制对象Object Graph:对象图...
    OchardBird阅读 961评论 0 2
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,032评论 0 4