為什么導(dǎo)入了SpringBootMaven插件打包結(jié)果不是SpringBoot的大Jar包,導(dǎo)致Jar包無(wú)法正常啟動(dòng)

最近遇到一個(gè)問題绑榴,自己直接通過Maven去建立一個(gè)SpringBoot項(xiàng)目,最終打包的結(jié)果卻并不是SpringBoot的打包結(jié)果盈魁,導(dǎo)致Jar包不能正常通過java -jar啟動(dòng)。

項(xiàng)目依賴很簡(jiǎn)單窃诉,如下面的所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wanna</groupId>
    <artifactId>maven-test-2</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.15</version>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.5.15</version>
        </dependency>
    </dependencies>
</project>

只是簡(jiǎn)單導(dǎo)入了一個(gè)SpringBoot的WebStarter和一個(gè)SpringBoot的Maven編譯器插件杨耙。

自己搗鼓了幾天都沒有結(jié)果赤套,在網(wǎng)上無(wú)意間發(fā)現(xiàn)了一篇文章說,將Maven插件的配置改為如下的方式珊膜,就可以容握。

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.15</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

實(shí)驗(yàn)了一下,最終發(fā)現(xiàn)確實(shí)可以车柠,能正常打包剔氏,也能正常運(yùn)行Jar包。

可是為什么呢竹祷?為什么加上這樣的配置之后就行谈跛。我之前的SpringBoot項(xiàng)目都是,直接導(dǎo)入插件就行塑陵。

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.15</version>
            </plugin>

剛剛我們的這個(gè)repackage是Maven插件的一個(gè)Mojo(RepackageMojo)感憾,于是我們需要弄清楚為什么這個(gè)Mojo沒生效。

于是開始去Debug MAVEN源碼令花,找到MAVEN當(dāng)中構(gòu)建Mojo的地方阻桅,代碼位置如下。

org.apache.maven.lifecycle.internal.DefaultLifecycleMappingDelegate#calculateLifecycleMappings

    public Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
                                                                        Lifecycle lifecycle, String lifecyclePhase )
        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
        MojoNotFoundException, InvalidPluginDescriptorException
    {
        /*
         * Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
         * is interested in, i.e. all phases up to and including the specified phase.
         */

        Map<String, Map<Integer, List<MojoExecution>>> mappings =
            new LinkedHashMap<>();

        for ( String phase : lifecycle.getPhases() )
        {
            Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<>();

            mappings.put( phase, phaseBindings );

            if ( phase.equals( lifecyclePhase ) )
            {
                break;
            }
        }

        /*
         * Grab plugin executions that are bound to the selected lifecycle phases from project. The effective model of
         * the project already contains the plugin executions induced by the project's packaging type. Remember, all
         * phases of interest and only those are in the lifecycle mapping, if a phase has no value in the map, we are
         * not interested in any of the executions bound to it.
         */

        for ( Plugin plugin : project.getBuild().getPlugins() )
        {
            for ( PluginExecution execution : plugin.getExecutions() )
            {
                // if the phase is specified then I don't have to go fetch the plugin yet and pull it down
                // to examine the phase it is associated to.
                if ( execution.getPhase() != null )
                {
                    Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( execution.getPhase() );
                    if ( phaseBindings != null )
                    {
                        for ( String goal : execution.getGoals() )
                        {
                            MojoExecution mojoExecution = new MojoExecution( plugin, goal, execution.getId() );
                            mojoExecution.setLifecyclePhase( execution.getPhase() );
                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
                        }
                    }
                }
                // if not then i need to grab the mojo descriptor and look at the phase that is specified
                else
                {
                    for ( String goal : execution.getGoals() )
                    {
                        MojoDescriptor mojoDescriptor =
                            pluginManager.getMojoDescriptor( plugin, goal, project.getRemotePluginRepositories(),
                                                             session.getRepositorySession() );

                        Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( mojoDescriptor.getPhase() );
                        if ( phaseBindings != null )
                        {
                            MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
                            mojoExecution.setLifecyclePhase( mojoDescriptor.getPhase() );
                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
                        }
                    }
                }
            }
        }

        Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<>();

        for ( Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet() )
        {
            List<MojoExecution> mojoExecutions = new ArrayList<>();

            for ( List<MojoExecution> executions : entry.getValue().values() )
            {
                mojoExecutions.addAll( executions );
            }

            lifecycleMappings.put( entry.getKey(), mojoExecutions );
        }

        return lifecycleMappings;

    }

這里的一個(gè)MojoExecution對(duì)象兼都,就是一個(gè)我們配置的Mojo嫂沉,如果我們?cè)趐lugin當(dāng)中添加了如下這樣的配置,那么這里就能構(gòu)建出來(lái)repackage這樣的一個(gè)MojoExecution扮碧,如果我們沒有添加输瓜,則會(huì)缺少了這樣的MojoExecution。

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.5.15</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

這里芬萍,我們開始懷疑尤揣,是在哪里悄悄的配置了repackage這個(gè)Mojo。

我們找到了SpringBootMavenPlugin的官方文檔:

https://docs.spring.io/spring-boot/docs/3.2.2/maven-plugin/reference/htmlsingle/

在第三章"Using the Plugin"當(dāng)中柬祠,有下面這樣的介紹北戏。

image.png

其中一條告訴了我們,我們?nèi)绻^承了"spring-boot-starter-parent"的話漫蛔,將會(huì)生成一個(gè)repackage goal的Execution(并且指定了executionId為repackage)嗜愈。

我們找到了spring-boot-starter-parent這個(gè)POM,發(fā)現(xiàn)其中定義的spring-boot-maven-plugin莽龟,確實(shí)通過execution標(biāo)簽去指定了repackage的goal蠕嫁。

        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <executions>
            <execution>
              <id>repackage</id>
              <goals>
                <goal>repackage</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <mainClass>${start-class}</mainClass>
          </configuration>
        </plugin>

這下明白了,默認(rèn)情況下spring-boot-maven-plugin并不會(huì)指定Maven的自動(dòng)打包毯盈,只是定義了repackage這個(gè)Mojo剃毒,我們通過Intellij可以看到。

image.png

如果我們想要在沒有spring-boot-starter-parent的情況下使用,就可以添加上如下的配置赘阀,去進(jìn)行開啟益缠。(實(shí)際上,沒有spring-boot-starter-parent的情況是很常見的基公,比如在一些大公司當(dāng)中幅慌,公司可能會(huì)自定義一些中間件,就可能會(huì)要求所有的項(xiàng)目統(tǒng)一導(dǎo)入公司的父POM*轰豆,此時(shí)就會(huì)導(dǎo)致我們無(wú)法使用spring-boot-starter-parent去作為父工程胰伍,就很可能需要用到手動(dòng)配置repackage)

                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市酸休,隨后出現(xiàn)的幾起案子骂租,更是在濱河造成了極大的恐慌,老刑警劉巖雨席,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菩咨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡陡厘,警方通過查閱死者的電腦和手機(jī)抽米,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)糙置,“玉大人云茸,你說我怎么就攤上這事“梗” “怎么了标捺?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)揉抵。 經(jīng)常有香客問我亡容,道長(zhǎng),這世上最難降的妖魔是什么冤今? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任闺兢,我火速辦了婚禮,結(jié)果婚禮上戏罢,老公的妹妹穿的比我還像新娘屋谭。我一直安慰自己,他們只是感情好龟糕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布桐磁。 她就那樣靜靜地躺著,像睡著了一般讲岁。 火紅的嫁衣襯著肌膚如雪我擂。 梳的紋絲不亂的頭發(fā)上衬以,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音扶踊,去河邊找鬼泄鹏。 笑死郎任,一個(gè)胖子當(dāng)著我的面吹牛秧耗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舶治,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼分井,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了霉猛?” 一聲冷哼從身側(cè)響起尺锚,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惜浅,沒想到半個(gè)月后瘫辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坛悉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年伐厌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裸影。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挣轨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出轩猩,到底是詐尸還是另有隱情卷扮,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布均践,位于F島的核電站晤锹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏彤委。R本人自食惡果不足惜鞭铆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望葫慎。 院中可真熱鬧衔彻,春花似錦、人聲如沸偷办。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)椒涯。三九已至柄沮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祖搓。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工狱意, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拯欧。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓详囤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親镐作。 傳聞我的和親對(duì)象是個(gè)殘疾皇子藏姐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353