首页 > 代码库 > (十三)Maven插件解析运行机制

(十三)Maven插件解析运行机制

这里给大家详细说一下Maven的运行机制,让大家不仅知其然,更知其所以然。

 

1.插件保存在哪里?

与我们所依赖的构件一样,插件也是基于坐标保存在我们的Maven仓库当中的。在用到插件的时候会先从本地仓库查找插件,如果本地仓库没有则从远程仓库查找插件并下载到本地仓库。

与普通的依赖构件不同的是,Maven会区别对待普通依赖的远程仓库与插件的远程仓库。前面提到的配置远程仓库只会对普通的依赖有效果。当Maven需要的插件在本地仓库不存在时是不会去我们以前配置的远程仓库查找插件的,而是需要有专门的插件远程仓库,我们来看看怎么配置插件远程仓库,在pom.xml加入如下内容:

 1 <pluginRepositories>
 2         <pluginRepository>
 3             <id>nexus</id>
 4             <name>nexus</name>
 5             <url>http://192.168.0.70:8081/content/groups/public/</url>
 6             <releases>
 7                 <enabled>true</enabled>
 8             </releases>
 9             <snapshots>
10                 <enabled>true</enabled>
11             </snapshots>
12         </pluginRepository>
13 </pluginRepositories>

大家可以发现,除了pluginRepositories和pluginRepository与以前配置远程仓库不同以外,其他的都是一样的,所代表的含义也是一样的。Maven的父POM中也是有内置一个插件仓库的,我现在用的电脑安装的是Maven 3.0.4版本,我们可以找到这个文件:${M2_HOME}/lib/maven-model-builder-3.0.4.jar,打开该文件,能找到超级父POM:\org\apache\maven\model\pom-4.0.0.xml,它是所有Maven POM的父POM,所有Maven项目都继承该配置。


我们来看看默认的远程插件仓库配置的是啥:

 1 <pluginRepositories>
 2     <pluginRepository>
 3       <id>central</id>
 4       <name>Central Repository</name>
 5       <url>http://repo.maven.apache.org/maven2</url>
 6       <layout>default</layout>
 7       <snapshots>
 8         <enabled>false</enabled>
 9       </snapshots>
10       <releases>
11         <updatePolicy>never</updatePolicy>
12       </releases>
13     </pluginRepository>
14 </pluginRepositories>

默认插件仓库的地址就是中央仓库咯,它关闭了对snapshots的支持,防止引入snapshots版本的插件而导致不稳定的构件。一般来说,中央仓库所包含的插件完全能够满足我们的需要,只有在少数情况下才要配置,比如项目的插件无法在中央仓库找到,或者自己编写了插件才会配置自己的远程插件仓库。

 

2.插件命令运行解析

我们来看这样一个命令:

mvn compiler:compiler

这个命令会调用maven-compiler-plugin插件并执行compiler目标,大家有木有觉得很神奇?我们在pom.xml中配置插件往往是这样:

1         <plugin>
2             <groupId>org.apache.maven.plugins</groupId>
3             <artifactId>maven-compiler-plugin</artifactId>
4             <version>3.1</version>
5             <configuration>
6                 <source>1.7</source> <!-- 源代码使用的开发版本 -->
7                 <target>1.7</target> <!-- 需要生成的目标class文件的编译版本 -->
8             </configuration>
9         </plugin>    

maven-compiler-plugin插件默认执行的目标为compiler,那么命令的完整写法应该是:mvn org.apache.maven.plugins:maven-compiler-plugin:3.1:compiler才对啊,为什么mvn compiler:compiler也能完美的执行?

 

我们来看看Maven到底干了些神马来做到如此牛逼的功能:

 

①插件默认groupId

Maven默认以org.apache.maven.plugins作为groupId,到这里我们的命令应该是长这样的:

mvn org.apache.maven.plugins:compiler:compiler

我们也可以配置自己默认的groupId,在Maven的settings.xml中添加如下内容,前面提过最好将settings.xml放在用户目录的.m2下:

1 <pluginGroups>
2     <!-- pluginGroup
3      | Specifies a further group identifier to use for plugin lookup.
4     <pluginGroup>com.your.plugins</pluginGroup>
5     -->
6     <pluginGroup>com.your.plugins</pluginGroup>
7 </pluginGroups>

不过说实在的,没必要动他就别去动他了,我们用Maven只是解决一些刚需的问题,没必要的设置就尽量不去动他,别把Maven搞得太复杂,虽然Maven的却有点小复杂,跟大家扯这些只是希望大家能够对maven理解的更深入那么一点点,并不是建议大家一定要去使用某些东西,大家在平时的开发中要谨记这一点。

 

②我们来看看Maven插件远程仓库的元数据org/apache/maven/plugins/maven-metadata.xml,Maven默认的远程仓库是http://repo.maven.apache.org/maven2/,所有插件元数据路径则是:http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-metadata.xml,我们找到compiler插件的元数据,如图:

技术分享

这里会根据prefix指定的前缀找到对应的artifactId,到这里我们的命令应该长成了这样:

mvn org.apache.maven.plugins:maven-compiler-plugin:compiler

 

③我们再根据groupId和artifactId找到maven-compiler-plugin插件单个的元数据,路径为http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml,如图:

技术分享

maven将所有的远程插件仓库及本地仓库元数据归并后,就能找到release的版本(maven3后为了保证项目构建的稳定性默认使用release版本),到这里命令就被扩展成为这样:

mvn org.apache.maven.plugins:maven-compiler-plugin:3.6.0:compiler

如果执行的是mvn compiler:compiler命令,由于maven-compiler-plugin的最新版本已经到了3.6.0,则默认会使用此版本。最后的compiler则是插件要执行的目标咯,看到这里大家应该明白mvn compiler:compiler命令为什么能够得到完美的运行了吧。

 

3.Maven超级POM

最后给大家把超级父POM贴出来,再次强调,如果我们没有在自己的pom.xml中配置相应的内容,则默认会使用超级父POM配置的内容。我现在用的电脑安装的是Maven 3.0.4版本,我们可以找到这个文件:${M2_HOME}/lib/maven-model-builder-3.0.4.jar,打开该文件,能找到超级父POM:\org\apache\maven\model\pom-4.0.0.xml,它是所有Maven POM的父POM,所有Maven项目都继承该配置。

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 
  3 <!--
  4 Licensed to the Apache Software Foundation (ASF) under one
  5 or more contributor license agreements.  See the NOTICE file
  6 distributed with this work for additional information
  7 regarding copyright ownership.  The ASF licenses this file
  8 to you under the Apache License, Version 2.0 (the
  9 "License"); you may not use this file except in compliance
 10 with the License.  You may obtain a copy of the License at
 11 
 12     http://www.apache.org/licenses/LICENSE-2.0
 13 
 14 Unless required by applicable law or agreed to in writing,
 15 software distributed under the License is distributed on an
 16 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17 KIND, either express or implied.  See the License for the
 18 specific language governing permissions and limitations
 19 under the License.
 20 -->
 21 
 22 <!-- START SNIPPET: superpom -->
 23 <project>
 24   <modelVersion>4.0.0</modelVersion>
 25 
 26   <repositories>
 27     <repository>
 28       <id>central</id>
 29       <name>Central Repository</name>
 30       <url>http://repo.maven.apache.org/maven2</url>
 31       <layout>default</layout>
 32       <snapshots>
 33         <enabled>false</enabled>
 34       </snapshots>
 35     </repository>
 36   </repositories>
 37 
 38   <pluginRepositories>
 39     <pluginRepository>
 40       <id>central</id>
 41       <name>Central Repository</name>
 42       <url>http://repo.maven.apache.org/maven2</url>
 43       <layout>default</layout>
 44       <snapshots>
 45         <enabled>false</enabled>
 46       </snapshots>
 47       <releases>
 48         <updatePolicy>never</updatePolicy>
 49       </releases>
 50     </pluginRepository>
 51   </pluginRepositories>
 52 
 53   <build>
 54     <directory>${project.basedir}/target</directory>
 55     <outputDirectory>${project.build.directory}/classes</outputDirectory>
 56     <finalName>${project.artifactId}-${project.version}</finalName>
 57     <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
 58     <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
 59     <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
 60     <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
 61     <resources>
 62       <resource>
 63         <directory>${project.basedir}/src/main/resources</directory>
 64       </resource>
 65     </resources>
 66     <testResources>
 67       <testResource>
 68         <directory>${project.basedir}/src/test/resources</directory>
 69       </testResource>
 70     </testResources>
 71     <pluginManagement>
 72       <!-- NOTE: These plugins will be removed from future versions of the super POM -->
 73       <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
 74       <plugins>
 75         <plugin>
 76           <artifactId>maven-antrun-plugin</artifactId>
 77           <version>1.3</version>
 78         </plugin>
 79         <plugin>
 80           <artifactId>maven-assembly-plugin</artifactId>
 81           <version>2.2-beta-5</version>
 82         </plugin>
 83         <plugin>
 84           <artifactId>maven-dependency-plugin</artifactId>
 85           <version>2.1</version>
 86         </plugin>
 87         <plugin>
 88           <artifactId>maven-release-plugin</artifactId>
 89           <version>2.0</version>
 90         </plugin>
 91       </plugins>
 92     </pluginManagement>
 93   </build>
 94 
 95   <reporting>
 96     <outputDirectory>${project.build.directory}/site</outputDirectory>
 97   </reporting>
 98 
 99   <profiles>
100     <!-- NOTE: The release profile will be removed from future versions of the super POM -->
101     <profile>
102       <id>release-profile</id>
103 
104       <activation>
105         <property>
106           <name>performRelease</name>
107           <value>true</value>
108         </property>
109       </activation>
110 
111       <build>
112         <plugins>
113           <plugin>
114             <inherited>true</inherited>
115             <artifactId>maven-source-plugin</artifactId>
116             <executions>
117               <execution>
118                 <id>attach-sources</id>
119                 <goals>
120                   <goal>jar</goal>
121                 </goals>
122               </execution>
123             </executions>
124           </plugin>
125           <plugin>
126             <inherited>true</inherited>
127             <artifactId>maven-javadoc-plugin</artifactId>
128             <executions>
129               <execution>
130                 <id>attach-javadocs</id>
131                 <goals>
132                   <goal>jar</goal>
133                 </goals>
134               </execution>
135             </executions>
136           </plugin>
137           <plugin>
138             <inherited>true</inherited>
139             <artifactId>maven-deploy-plugin</artifactId>
140             <configuration>
141               <updateReleaseInfo>true</updateReleaseInfo>
142             </configuration>
143           </plugin>
144         </plugins>
145       </build>
146     </profile>
147   </profiles>
148 
149 </project>
150 <!-- END SNIPPET: superpom -->

很多插件是超级父POM当中并没有配置的,如果用户使用某个插件时没有设定版本,那么则会根据我上述所说的规则去仓库中查找可用的版本,然后做出选择。在Maven2中,插件的版本会被解析至latest。也就是说,当用户使用某个非核心插件且没有声明版本的时候,Maven会将版本解析为所有可用仓库中的最新版本,latest表示的就是最新版本,而这个版本很有可能是快照版本。

当插件为快照版本时,就会出现潜在的问题。昨天还好好的,可能今天就出错了,其原因是这个快照版本发生了变化导致的。为了防止这类问题,Maven3调整了解析机制,当插件没有声明版本的时候,不再解析至latest,而是使用release。这样就避免了由于快照频繁更新而导致的不稳定问题。但是这样就好了吗?不写版本号其实是不推荐的做法,例如,我使用的插件发布了一个新版本,而这个release版本与之前的版本的行为发生了变化,这种变化依然可能导致我们项目的瘫痪。所以使用插件的时候,应该一直显式的设定版本,这也解释了Maven为什么要在超级父POM中为核心插件设定版本咯。

 

结束语:当你感到悲哀痛苦时,最好是去学些什么东西,学习会使你从悲哀痛苦中走出来,学习会使你永远立于不败之地。说实在的,不要太在意眼前所发生的一切,更重要的是培养自己的个人能力,如今待在公司亦或者跳槽,决定你能不能继续走下去的一定是你的个人能力,作为年轻人,在公司更看重的不应该是薪水的高低,而是公司能给你带来多大的成长环境。找个好的公司其实不比找个合适的女朋友简单,所以作为年轻人我们一定要不断的提升个人能力,就跟找女朋友似的,往往就是你越有本事就越能够不将就,你个人能力越强则越有选择公司的资本。

 

可爱博主:AlanLee

博客地址:http://www.cnblogs.com/AlanLee

本文出自博客园,欢迎大家加入博客园。

 

(十三)Maven插件解析运行机制