【曹工雜談】Maven和Tomcat能有啥聯絡呢,都穿打補丁的衣服嗎

三國夢迴發表於2021-09-07

Maven和Tomcat能有啥聯絡呢,都穿打補丁的衣服嗎

前奏

我們上篇文章,跟大家說了下,怎麼除錯maven外掛的程式碼,注意,是外掛的程式碼。外掛,是要讓主框架來執行的,主框架是誰呢,就是maven core,可以稱之為maven核心吧。

maven核心,類似於tomcat,而maven外掛就類似於我們部署在tomcat中的webapp應用。估計有人覺得,這個類比有點生硬,不過我也是有我自己的依據的。

下面開始正文。

tomcat的類分散在哪幾處

按照簡單的模型來分,三處:

1、bin下邊的啟動類等

2、lib下的tomcat核心框架類

3、webapp的類

這個就不說了,就是大家的業務類。

maven和tomcat的相似之處

下邊,我們看maven的jar包的分散情況。

1、啟動類

在maven home的boot目錄下

2、maven core

3、外掛程式碼

分佈在本地倉庫中的目錄中。

彙總一下,這兩個框架,執行過程中需要用到的jar包,都分散在了三個地方。按照我們的理解,執行順序是:

從啟動類出發 --》 載入框架核心程式碼 --》 框架去載入外掛/webapp程式碼來執行。

當然了,大家可以想想啊,換成你來寫這個tomcat、maven,你怎麼辦?三種程式碼,三個地方,肯定要三個類載入器吧。第一個類載入器,只能載入到啟動類那幾個包;要去呼叫框架核心,是不是又得新建一個類載入器;框架核心,要去呼叫外掛/webapp程式碼,又要新疆類載入器吧。

中間怎麼銜接啊?

maven clean時,到底發生了什麼(啟動類階段)

如果我們直接在命令列執行mvn clean,實際上是呼叫了 如下命令:

這個命令是啥呢,我之前工作多年的經驗告訴我,這是個二進位制,開啟必須是一串亂碼啊;然後之前對maven也沒好奇心,沒研究過,最近才知道,這他麼是個shell/cmd。

原來是個java命令?? 果然啊,經驗主義還是要不得,大意了大意了。

我這邊是個windows電腦,實在不方便列印出來最終的執行命令,於是採用了一些迂迴方式。

在我的F:\tools\apache-maven-3.8.1-bin\apache-maven-3.8.1\bin目錄下,開啟git bash,用shell來執行:

大家可以看下,這裡的classpath中的jar,就是我前文提到的,maven home的boot目錄下的 jar,啟動類,就是在這個jar裡面。

這裡,大家可以想想啟動類的目標是啥,是要去載入框架核心。對於啟動類來說,重點在於:框架類的程式碼在哪裡呢?是靠預設約定嗎,還是讀一個什麼配置檔案。

答案就是配置檔案。

可以看看上面的圖裡,有一條:

-Dclassworlds.conf=/f/tools/apache-maven-3.8.1-bin/apache-maven-3.8.1/bin/m2.conf

這個檔案,我們開啟看一下:

main is org.apache.maven.cli.MavenCli from plexus.core

set maven.conf default ${maven.home}/conf

[plexus.core]
load       ${maven.conf}/logging
optionally ${maven.home}/lib/ext/*.jar
load       ${maven.home}/lib/*.jar

就是個文字檔案啊,裡面好像寫了些似是而非的東西,不能看懂得多了,但是看得懂一點點。

這裡呢,我提煉一下關鍵資訊,其實有三點:

  1. 接下來要把執行權交給誰?

    這個就是從main is org.apache.maven.cli.MavenCli from plexus.core這一行,org.apache.maven.cli.MavenCli就是接下來的框架核心程式碼的啟動人

  2. 主配置檔案在哪裡

    在maven安裝目錄的conf下,這裡面有我們的settings.xml,這個大家都曉得了哈

  3. 框架核心程式碼在哪裡

    這就交給下面幾位來指定了

    load       ${maven.conf}/logging
    optionally ${maven.home}/lib/ext/*.jar
    load       ${maven.home}/lib/*.jar
    

maven clean時,到底發生了什麼(框架核心類階段)

這個階段,內容就太多了,${maven.home}/lib/*.jar這足足十來個jar包,後面有的是時間說。

我們現在重要的是,把流程先梳理通,框架核心的目標,就是根據引數,找到對應的外掛程式碼,載入進來,然後執行。

我們前面,傳參就是clean,clean其實是代表了clean這個生命週期裡的clean階段,而clean階段,繫結的外掛就是:maven-clean-plugin

那這個外掛的程式碼,去哪裡找呢?這次,就是maven 約定優於配置的理念的體現了,沒有采用配置檔案,外掛和我們的業務依賴一樣,都放在本地倉庫,本地倉庫找不到,就去遠端中央倉庫下載。

我們這裡,本地已經有了:

拿到jar後,就是建立一個專供該外掛的類載入器,來載入這個外掛的jar,以及外掛依賴的jar。

外掛依賴的jar,能在哪裡看呢,在這個外掛的描述檔案裡,描述檔案就是下邊這個,它描述了外掛的方方面面,比如有哪些可以執行的goal、goal的引數是啥,當然,也包括了外掛依賴的jar。

外掛依賴如下:

maven clean時,到底發生了什麼(外掛被框架核心執行階段)

框架是被執行的。為什麼叫:被執行。就是,一切的掌控邏輯,都在框架核心中。

外掛呢,是要按照規範來的,誰的規範,框架核心的規範,規範是啥,就是框架核心定的一個介面:

public interface Mojo {
	// 外掛邏輯寫在這個裡面
    void execute() throws MojoExecutionException, MojoFailureException;

    void setLog(Log var1);

    Log getLog();
}

clean外掛的實現邏輯:

框架核心做了啥,就是載入org.apache.maven.plugin.clean.CleanMojo,然後強制向上轉型成Mojo,然後優雅地用多型來執行execute方法,呼叫外掛的實際邏輯即可。

maven上述執行過程中的幾個類載入器例項賞析

我在外掛裡,睡了1000秒,然後執行 jmap -dump:live,format=b,file=heap16380.bin 16380(16380是我maven這個java程式的pid)

把堆dump下來後,還是照例分析一把,看看堆裡有哪些類載入器:

一共18個,還真不少。不過很多都是不用關心的,上圖中,我們只關注三個:

1、啟動時的載入器-AppClassloader

2、框架核心類載入器

如我們所見,確實都是 lib下的jar。

3、外掛類載入器

如我們所見,去本地倉庫載入了外掛的jar。

總結

本來吧,我是想講maven框架核心的除錯環境搭建,結果,就來了個這,畢竟,不把這個說清楚,環境搭建感覺也說不清。。

環境搭建等下篇,see u,以上。

相關文章