【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
Maven底层容器Plexus Container的前世今生,一代芳华终落幕
前言
说实话,我非常地纠结,大家平时只是用Maven,对于内部的实现其实也不关心,我现在非要拉着大家给大家讲。这就有个问题,Maven的内部,还是相对没那么简单的,也算是个不小的工程了。
核心功能,大家是清楚的,内部的执行流程,大家也大概猜的出来:
- 解析命令行参数
- 准备各种上下文,简单的mvn clean就涉及到当前项目的元数据pom.xml、settings.xml(主要是本地、远程仓库相关);
- 根据mvn clean或者mvn compile,找到对应的生命周期(大家应该都知道maven的三个lifecycle吧);然后看看要执行生命周期中的哪些阶段,顺序是啥(这个和打包方式也有关,jar/war时,打包组件就不同);
- 顺序执行生命周期中的每个阶段的时候,去找到对应的绑定的插件,然后执行插件(执行插件又包括:根据插件坐标,去本地仓库/远程仓库找对应的artifact,以及解析artifact中的插件元数据,元数据中会告诉你,支持传哪些参数,参数类型是啥)
- 执行完成后,返回结果。
这么一个不小的工程,想必,还是会有很多对象互相依赖的,在没有依赖注入前,都是靠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的工作就是和各种文件、目录打交道,这期间,会沉淀出来很多公用组件:
- 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>归档相关的,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>cli相关,Plexus CLI
编译相关,Plexus Compiler
Digest/Hashcode相关,Plexus Digest / Hashcode Components
国际化相关,i18n
还有些其他的,我懒得列举了,大家自己看吧,https://web.archive.org/web/20150225072024/http://plexus.codehaus.org/plexus-components/
- IO相关的,
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。大家可以拉代码下来。
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
【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕的更多相关文章
- 【曹工杂谈】Maven IOC容器的下半场:Google Guice
Maven容器的下半场:Guice 前言 在前面的文章里,Maven底层容器Plexus Container的前世今生,一代芳华终落幕,我们提到,在Plexus Container退任后,取而代之的底 ...
- 【曹工杂谈】Maven源码调试工程搭建
Maven源码调试工程搭建 思路 我们前面的文章<[曹工杂谈]Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗>分析了Maven大体的执行阶段,主要包括三个阶段: 启动类阶段,负责 ...
- 【曹工杂谈】Mysql-Connector-Java时区问题的一点理解--写入数据库的时间总是晚13小时问题
背景 去年写了一篇"[曹工杂谈]Mysql客户端上,时间为啥和本地差了整整13个小时,就离谱",结果最近还真就用上了. 不是我用上,是组内一位同事,他也是这样:有个服务往数据库in ...
- 曹工杂谈:Spring boot应用,自己动手用Netty替换底层Tomcat容器
前言 问:标题说的什么意思? 答:简单说,一个spring boot应用(我这里,版本升到2.1.7.Release了,没什么问题),默认使用了tomcat作为底层容器来接收和处理连接. 我这里,在依 ...
- 【曹工杂谈】Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗
Maven和Tomcat能有啥联系呢,都穿打补丁的衣服吗 前奏 我们上篇文章,跟大家说了下,怎么调试maven插件的代码,注意,是插件的代码.插件,是要让主框架来执行的,主框架是谁呢,就是maven ...
- 曹工杂谈--使用mybatis的同学,进来看看怎么在日志打印完整sql吧,在数据库可执行那种
前言 今天新年第一天,给大家拜个年,祝大家新的一年里,技术突突突,头发长长长! 咱们搞技术的,比较直接,那就开始吧.我给大家看看我demo工程的效果(代码下边会给大家的): 技术栈是mybatis/m ...
- 【曹工杂谈】Maven IOC 容器-- Guice内部有什么
Google Guice容器内部有什么 前言 Maven系列,好几天没写了,主要是这几天被Google Guice卡住了,本来是可以随便带过Guice,讲讲guice的用法就够了(这个已经讲了,在前面 ...
- 【曹工杂谈】详解Maven插件调试方法
前言 今年的更新频率简直是降至冰点了,一方面平时加班相对多一些了,下班只想玩手机:另一方面,好像进了大厂后,学习动力也很低了,总之就,很懒散,博客的话,今年都才只更新了不到5篇. 现在慢慢有一点状态, ...
- 【曹工杂谈】说说Maven框架和插件的契约
说说Maven框架和插件的契约 前言 Maven框架就像现在公司内的各种平台方,规定一些契约,然后想办法拉动业务方,一起在这个平台上去做生态共建.Maven也是这样,其实它就是一个插件执行的框架,Ma ...
随机推荐
- 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件)
;~ 在屏幕上搜索图片并返回图片所在位置的坐标的AutoHotkey脚本源代码(类似大漠插件) ; https://www.autohotkey.com/boards/viewtopic.php?t ...
- SQL Server截取字符串(经纬度)
DECLARE @var VARCHAR(50) SET @var ='116.404556|39.915156' 方式一: SELECT CASE WHEN ISNULL(@var,'') < ...
- MongoDB 批量插入和循环插入性能测试
一万条数据批量插入和循环插入 循环插入 var startTime = (new Date()).getTime() var db = connect('log') for(var i = 0;i&l ...
- 用Matlab求解微分方程
用Matlab求解微分方程 解微分方程有两种解,一种是解析解,一种是数值解,这两种分别对应不同的解法 解析解 利用dsolve函数进行求解 syms x; s = dsolve('eq1,eq2,.. ...
- 跟我一起写 Makefile(十)
四.foreach 函数 foreach函数和别的函数非常的不一样.因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语 ...
- MyBatis学习06(动态SQL和缓存)
10.动态SQL 10.1 什么是动态SQL 动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 官网描述: MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或 ...
- Prometheus alertmanager邮件发送+grafana告警展示
前言 前面一篇博客,我已经介绍了prometheus如何监控mysql. 这一篇我来介绍如何通过alertmanger进行告警邮件发送(微信或钉钉类似,因为需要企业帐户,我就不试了),以及如何通过gr ...
- 设计模式:单例模式的使用和实现(JAVA)
单例模式的使用 jdk和Spring都有实现单例模式,这里举的例子是JDK中Runtime这个类 Runtime的使用 通过Runtime类可以获取JVM堆内存的信息,还可以调用它的方法进行GC. p ...
- Jetpack Compose学习(2)——文本(Text)的使用
原文: Jetpack Compose学习(2)--文本(Text)的使用 | Stars-One的杂货小窝 对于开发来说,文字最为基础的组件,我们先从这两个使用开始吧 本篇涉及到Kotlin和DSL ...
- STM32—驱动BT-06蓝牙模块传输数据
文章目录 BT-06简介 数据透传 配置串口 USART1初始化函数 USART2初始化函数 USART2的NVIC配置 USART1串口重映射 BT-06简介 BT06蓝牙模块是专为智能无线数据传输 ...