maven一篇文章就够了(上)

一:maven的发展历程

 在maven发展之前,传统的jar包管理我们一般会用ant+lvy来管理jar包,它有显而易见的两个缺点,

缺点一:需要我们来手动的来打jar包(build as),然后把打过得包放到我们规定的目录下(虽然可以进行特殊的处理引用本地的应用,不需要打包,但是前提条件就是你的有这个应用的源码)。
缺点二:每一个应用都需要有相同的配置,重复的工作不停的在做,这样的话相当月重复造轮子,这也不太符合编程语言的原则。
基于这两点:我们从农业社会开始向工业社会转型,开始步入maven的时代。

二,maven介绍

2.1,convention over configuration(约定优于配置原则)

在介绍maven之前我们先记住一个原则:约定优于配置的原则(比如我们建立的多个应用之间的目录结构是一致的),下面的配置是在主pom文件中的,在下面的maven目录结构中会讲到的。(超级pom文件)
比如上面的地方,我们建立的多个应用之间我们的目录结构都是一致的,这样我们会在主(父)pom文件中可以进行统一的设置。(后面我们还会多次提到这个原则)

2.2,maven的下载安装配置(略)

2.3,maven的目录结构解析

maven是java代码写的。
下面通过两张图来解析一下,更加直接一点。

 

在这里附上超级pom.xml的配置
<?xml version="1.0" encoding="UTF-8"?>
 
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at
 
    http://www.apache.org/licenses/LICENSE-2.0
 
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->
 
<!-- START SNIPPET: superpom -->
<project>
  <modelVersion>4.0.0</modelVersion>
 
  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
 
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>
 
  <build>
    <directory>${project.basedir}/target</directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <pluginManagement>
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.3.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
 
  <reporting>
    <outputDirectory>${project.build.directory}/site</outputDirectory>
  </reporting>
 
  <profiles>
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->
    <profile>
      <id>release-profile</id>
 
      <activation>
        <property>
          <name>performRelease</name>
          <value>true</value>
        </property>
      </activation>
 
      <build>
        <plugins>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-source-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-javadoc-plugin</artifactId>
            <executions>
              <execution>
                <id>attach-javadocs</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
          <plugin>
            <inherited>true</inherited>
            <artifactId>maven-deploy-plugin</artifactId>
            <configuration>
              <updateReleaseInfo>true</updateReleaseInfo>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
 
</project>
<!-- END SNIPPET: superpom -->

2.4,maven的settings.xml配置文件解读

mirrors本人常用的地址
<mirror> 
              <id>alimaven</id> 
              <name>aliyun maven</name> 
              <url>http://maven.aliyun.com/nexus/content/groups/public/</url> 
              <mirrorOf>central</mirrorOf>         
            </mirror>
            <mirror>
                  <id>ui</id>
                  <mirrorOf>central</mirrorOf>
                  <name>Human Readable Name for this Mirror.</name>
                  <url>http://uk.maven.org/maven2/</url>
            </mirror>
            <mirror>
            <id>osc</id>
            <mirrorOf>central</mirrorOf>
            <url>http://maven.oschina.net/content/groups/public/</url>
        </mirror>
        <mirror>
            <id>osc_thirdparty</id>
            <mirrorOf>thirdparty</mirrorOf>
            <url>http://maven.oschina.net/content/repositories/thirdparty/</url>
        </mirror>

 

2.5,pom.xml文件讲解

<modelVersion>4.0.0</modelVersion>
maven的版本号:就是我们在上面说的maven-model-builder-3.2.1里面的超级pom文件中定义的。
<groupId>com.qingruihappy</groupId>
一般都是公司域名前面加上com
<artifactId>qingruihappy_duoxiancheng</artifactId>
就是应用的名称
<packaging>war</packaging>
包的类型jar,war,pom(主要就是多个应用之间的父级,聚合)
<version>0.0.1-SNAPSHOT</version>
版本号
<properties>标签,父pom中的一些参数。类似于常量一样,统一版本号,不用写在后面的每一个配置中,同时它本身也可以是变量的,例如下面带红色圈起来的。

 

下面我们来着重讲一下 dependencyManagement这个配置
1. 只能出现在父pom
2. 统一版本号
3. 声明 (子POM里用到再引)
既然已经dependencies为什么还要有dependencyManagement呢?
考虑这个问题之前,我们先考虑一个问题在父pom文件中dependencyManagement定义的jar包依赖,在子目录中能应用到吗?
答案是不能呢,那为什么还要在父目录中的dependencyManagement定义dependencies依赖jar包呢?
我们来看一下子目录中的pom文件
是不是有点理解了,主要就是虽然我们用dependencyManagement定义了依赖,子目录不会自动的引用父目录中的引用,需要我们在子目录中在写一遍,但是我们写的方式完全不一样了,我们不需要写版本号,版本的控制还是在父目录中,避免出现版本号不一致的情况。
还有一点就是,假如我们不用这个标签的话,子类统一引用父类的pom文件,这样就会把我们子pom文件用不到的jar包也给依赖进来,这一点有点类似于声明式事物。(例如我们经常用到的httpclient用到的比较多最好在父类中统一版本号)。
dependencyManagement综上所述,一句话来概括就是,它的作用就是,版本号在父pom,用不用子pom决定。
 
dependencies下的scope属性
每个依赖项的Scope选项进行该jar包的相关操作设置,默认为compile,根据需要调整设置:
1、compile设置编译范围内有效,在编译和打包时都会将依赖项加载进去,默认设置。
2、test设置测试范围内有效,只在测试时使用,编译和打包时都不会加载该项,这个就是为什么我们有时候test目录下报错,但是不会影响本地tomact的启动,因为它是不会编译的。
最常用的就是complie和test
3、provided设置编译和测试的范围内有效,打包时不会加载该项。
对于第三方jar包,传递依赖到war包的,但发布时并不需要的。
如:我们项目中使用了webwork-2.2.3.jar。可以我们在打包后发现在war下的lib中多了spring-web-1.2.jar,可是我们项目并不需要这个jar。
第一种办法:借用provided
虽然provided的本意是指jdk或者容器提供的,只是编译中使用,但不会打到war中,但我们也可借用。
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>1.2</version>
    <scope>provided</scope>
</dependency>
第二种办法: 使用exclusions; (效果与第一种相同)
<dependency>
    <groupId>opensymphony</groupId>
    <artifactId>webwork</artifactId>
    <version>2.2.3</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </exclusion>
    </exclusions>
</dependency>
4、runtime设置在运行时加载该依赖项,但是编译时不依赖。
这种场景很少用的。
 
exclusions标签
主要解决jar包冲突的,
比如httpclient
我们可能在多个jar包中用到它了,但是引起jar包冲突了,我们就需要把在父类中定义统一的版本号,同时在子pom中排出掉就行了。
它的书写规范就是把 <groupId> 和 <artifactId>作为唯一的表示排出掉就行了,例如下面的案例
还有好多配置上面是最主要的。用到在说
<name>qingruihappy_duoxiancheng Maven Webapp</name>
<url>http://maven.apache.org</url>

2.6, 依赖传递

第一列表示直接依赖的scope,第一行表示间接依赖的scope
compile test provided runtime
compile compile - - runtime
test test - - test
provided provided - provided provided
runtime runtime - - runtime
知道有上面的存在就行了,一般很少用到的。

2.7,依赖仲裁:

我们来看上面的案例:
当web即依赖1.1-common 有依赖 1.0common的时候它最终选择哪个呢?
最短路径原则:选择1.0-common
假如出现上面的情况:路劲长短都是一样的,那么会依赖谁呢?
加载先后的顺序:
这个时候就会根据我们pom.xml文件写的顺序,谁写在前面就依赖谁。
 
 

2.8,maven的声明周期

 们在用maven构建java项目时,最常用的打包命令有mvn clean ,mvn package、mvn install、deploy,这四个命令都可完成打jar包或war(当然也可以是其它形式的包)的功能。

但是这并不是maven的生命周期,只是生命周期的一部分,下面这张图就是maven的整个生命周期。

 这个上面就是maven的全部的声明周期,但是我们现在只说一下标注黄色的主要的命名,它的声明周期一般是从左往右,从上到下的。

执行后面的命令的时候都会把前面的命令执行一遍。

其实在这个目录下我们可以看到maven 声明周期的插件

 我们借鉴网上https://blog.csdn.net/zhaojianting/article/details/80321488这篇网站来写一下。

我们先来看一张图

 

 可以看到整个执行过程包含了:1.clean 2.resources 3.compile 4.testResources 5.testCompile 6.test 7.jar 8.install;接下来详细说下各个插件的具体的作用;

2.8.1:clean插件maven-clean-plugin:2.5

clean插件是一个独立的阶段,功能是删除当前项目的target目录;这个自己也可以测试下,执行之后就是把target目录删除了而已;

2.8.2:resources插件maven-resources-plugin:2.6

resources插件的功能是把src/main/resources目录的文件拷贝到target/classes目录下;如果不存在src/main/resources目录,则不会做任何处理,测试期间,可以创建一个resources目录,里面添加个1.txt文件,然后执行resources插件,结果如图所示
resource插件的功能就是把项目需要的配置文件拷贝到指定的目当,默认是拷贝src\main\resources目录下的件到classes目录下,当然可以自己来配置源目录和输出目录。resources插件一般不单独执行,complie插件执行时会先调用resources插件。

2.8.3:compile插件maven-compiler-plugin

compile插件执行时,会先执行resources插件,主要的作用就是把src/main/java代码编译成字节码生成class文件,输出到targe/classes目录下;执行效果如图

 

2.8.4:.单元测试使用的插件testResource,testCompile

类似于resources和compile,只不过这两个类主要用于对单元测试的资源文件和代码进行编译;生成的文件位于target/test-classes下面;

有时候可以使用mvn -Dmaven.test.skip=true 跳过该步骤

 

2.8.5:package  maven-jar-plugin

这个插件是把class文件,resources文件打包成一个jar包,依赖包是不在里面包含的;常用的打包的插件有maven-jar-plugin、maven-assembly-plugin、maven-shade-plugin三种;生成的jar包位于target目录下;

2.8.6:install    maven-install-plugin

install是把构建好的artifact部署到本地仓库中;这样本地的其他项目依赖于本项目的jar时可以直接从本地仓库去获取,而不用到远端的私服上去下载;

2.8.7:.deploy

deploy是将本地的jar部署到远端的仓库;需要在maven的setting.xml中配置私服的用户名和密码;还需要再pom.xml做配置;

<distributionManagement>  
   <repository>  
     <id>releases</id>  
     <name>Internal Releases</name>  
     <url>http://localhost:8081/nexus/content/repositories/thirdparty</url>  
   </repository>  
   <snapshotRepository>  
     <id>releases</id>  
     <name>Internal Releases</name>  
     <url>http://localhost:8081/nexus/content/repositories/thirdparty</url>  
   </snapshotRepository>
 </distributionManagement> 

2.8.8:总结(重要的命名)

mvn clean package依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)等7个阶段。
mvn clean install依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install等8个阶段。
mvn clean deploy依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install、deploy等9个阶段。

 由上面的分析可知主要区别如下,

package命令完成了项目编译、单元测试、打包功能,但没有把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库
install命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程maven私服仓库
deploy命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库

  

猜你喜欢

转载自www.cnblogs.com/qingruihappy/p/10398649.html