Web基础之Maven

Maven是一个优秀的项目管理工具,可以很轻松的管理项目。

POM和LifeCycle

POM:Project Object Model。也就是项目模型,简单来说就是对项目进行建模,既然是建模,那就会有一些属性来定义这个项目。而配置文件pom.xml就是以xml形式描述这个建模,所以里面会有一些项目特定的属性,比如:groupId、artifactId、version……

那么Lifecycle又是什么呢?翻译过来就是生命周期,在项目构建过程中有着不同的阶段(phase),总共有多少个阶段呢?

一个标准的Lifecycle有着以下几个阶段:

validate: 用于验证项目的有效性和其项目所需要的内容是否具备
initialize:初始化操作,比如创建一些构建所需要的目录等。
generate-sources:用于生成一些源代码,这些源代码在compile phase中需要使用到
process-sources:对源代码进行一些操作,例如过滤一些源代码
generate-resources:生成资源文件(这些文件将被包含在最后的输入文件中)
process-resources:对资源文件进行处理
compile:对源代码进行编译
process-classes:对编译生成的文件进行处理
generate-test-sources:生成测试用的源代码
process-test-sources:对生成的测试源代码进行处理
generate-test-resources:生成测试用的资源文件
process-test-resources:对测试用的资源文件进行处理
test-compile:对测试用的源代码进行编译
process-test-classes:对测试源代码编译后的文件进行处理
test:进行单元测试
prepare-package:打包前置操作
package:打包
pre-integration-test:集成测试前置操作
integration-test:集成测试
post-integration-test:集成测试后置操作
install:将打包产物安装到本地maven仓库
deploy:将打包产物安装到远程仓库

在执行任意一个阶段时,之前的每个阶段都会执行。

注意,以上的每个阶段只是一个约定,并没有说每个阶段具体干什么。这有点类似接口,约定了一个项目需要有这些过程,但是每个过程具体干什么需要由我们自己去指定。这里再引入一个概念MOJO。什么是MOJO,官方解释是可执行的goal(目标),下面是stackoverflow上的高票答案:

What is a Mojo? A mojo is a Maven plain Old Java Object. Each mojo is an executable goal in Maven, and a plugin is a distribution of one or more related mojos.

In short, a mojo is a maven goal, to extend functionality not already found in maven.

翻译一下就是MOJO就是一个可执行对象(goal,目标),这个对象可以获得已经在maven里面定义过的功能。而我们需要做的就是把这个可执行对象和具体的阶段绑定起来。

在哪里绑定呢?在pom.xml里面的<build>属性里,因此一个plugins如下:

<!--使用的插件列表 。 -->
<plugins>
<plugin>
<groupId></groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version> <!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。 -->
<executions>
<execution> <!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标 -->
<id>assembly</id> <!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段 -->
<phase>package</phase> <!--配置的执行目标 -->
<goals>
<goal>single</goal>
</goals> <!--配置是否被传播到子POM -->
<inherited>false</inherited> </execution>
</executions> <!--作为DOM对象的配置,配置项因插件而异 -->
<configuration>
<finalName>${finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptor>assembly.xml</descriptor>
</configuration> <!--是否从该插件下载Maven扩展(例如打包和类型处理器), -->
<!--由于性能原因,只有在真需要下载时,该元素才被设置成true。 -->
<extensions>false</extensions> <!--项目引入插件所需要的额外依赖 -->
<dependencies>
<dependency>...</dependency>
</dependencies> <!--任何配置是否被传播到子项目 -->
<inherited>true</inherited> </plugin>
</plugins>

上例就将single这个goal绑定到了package这个phase。

这样虽然指定了要做什么,但是并没有在哪做、用什么做。这里需要说一下Maven的理念就是convention over configuration(约定优于配置)。这一点和ant有非常大的区别,例如使用ant来进行编译时,我们需要指定源文件的位置,输出文件的位置,javac的位置,classpath... ...在maven中这些都是不需要,若没有手动配置,maven默认从<项目根目录>/src/main/java这个目录去查找Java源文件,编译后的class文件会保存在<项目根目录>/target/classes目录。在maven中,所有的PO都有一个根对象,就是Super POM。Super POM中定义了所有的默认的配置项。Super POM对应的pom.xml文件可以在maven安装目录下lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml中找到。

参考Maven内部原理解析


简单使用

仓库

Maven将所有的jar包都集中在一个叫做“仓库”的地方,一个Maven项目需要使用到某个jar包时会在其项目中指向这个jar包,具体表现就是pom.xml中添加了坐标。

仓库分为本地、私服、远程仓库。就像瓶子里没有盐了就去柜子里找,柜子里也没有的话那就只能去超市买了,瓶子、柜子、超市分别对应本地仓库、私服、远程公共仓库。

生命周期

maven拥有三套相互独立的生命周期,分别是cleandefaultsite。clean 生命周期的目的是清理项目 ,default 生命周期的作用是构建项目 ,site 生命周期的目的是构建项目站点 。每个生命周期都有各自的阶段,上面罗列出的是default的各个阶段。下面是几个比较重要的阶段:

clean生命周期

clean生命周期的目的是清理项目,它包含三个阶段:

  1. pre-clean 执行一些清理前需要完成的工作;
  2. clean 清理上一次构建生成的文件;
  3. post-clean 执行一些清理后需要完成的工作;

default生命周期

​default生命周期定义了真正构建项目需要执行的所有步骤,它是所有生命周期中最核心的部分。其中的重要阶段如下:

  1. compile :编译项目的源码,一般来说编译的是src/main/java目录下的java文件至项目输出的主classpath目录中;
  2. test :使用单元测试框架运行测试,测试代码不会被打包或部署;
  3. package :接收编译好的代码,打包成可以发布的格式,如jar和war;
  4. install: 将包安装到本地仓库,共其他maven项目使用;
  5. deploy :将最终的包复制到远程仓库,供其他开发人员或maven项目使用;

site生命周期

​site生命周期的目的是建立和发布项目站点,maven能够基于pom文件所包含的项目信息,自动生成一个友好站点,方便团队交流和发布项目信息。该生命周期中最重要的阶段如下:

  1. site :生成项目站点文档;

maven可以使用命令行直接调用命令。

Maven 命令:

mvn clean:调用clean生命周期的clean阶段,清理上一次构建项目生成的文件;
mvn compile :编译src/main/java中的java代码;
mvn test :编译并运行了test中内容 ;
mvn package:将项目打包成可发布的文件,如jar或者war包;
mvn install :发布项目到本地仓库 ;

pom.xml介绍

<!-- xml文档声明 -->
<?xml version="1.0" encoding="UTF-8"?>
<!--
xmlns即xml name space, 本xml命名空间(命名空间出现是为了防止xml出现冲突)
xmlns:xsi, 约定了前缀为xsi对应的唯一字符串,即Schema约束(xsd)命名空间(业界默认)
xsi:schemaLocation, 这一行其实是 xsi:schemaLocation = "键" “值” 的形式,即 xsi 命名空间下 schemaLocation 元素的值为一个由空格分开的键值对。
不过这些定义不是太重要
-->
<!-- project pom文件的根节点 -->
<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>: 声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此,但它仍然是必不可少的,目前POM模型版本是4.0.0 -->
<modelVersion>4.0.0</modelVersion> <!-- <groupId> :maven项目组织id标识符,一般是公司域名倒过来写 -->
<groupId>com.bilibili.maven</groupId> <!-- <artifactId>:项目的标识符,即项目名 -->
<artifactId>maven-web2</artifactId> <!-- <version>:项目的版本号 -->
<version>1.0-SNAPSHOT</version> <!-- <packaging>:maven项目的打包方式一般配置jar或者war -->
<packaging>war</packaging>
</project>

xml头部声明参考这篇博客

对于jar、war:

Jar文件(扩展名为. Jar,Java Application Archive)包含Java类的普通库、资源(resources)、辅助文件(auxiliary files)等

War文件(扩展名为.War,Web Application Archive)包含全部Web应用程序。在这种情形下,一个Web应用程序被定义为单独的一组文件、类和资源,用户可以对jar文件进行封装,并把它作为小型服务程序(servlet)来访问。

Ear文件(扩展名为.Ear,Enterprise Application Archive)包含全部企业应用程序。在这种情形下,一个企业应用程序被定义为多个jar文件、资源、类和Web应用程序的集合。

每一种文件(.jar, .war, .ear)只能由应用服务器(application servers)、小型服务程序容器(servlet containers)、EJB容器(EJB containers)等进行处理。

参考

依赖管理

Maven的一个核心功能就是管理项目依赖。在<dependencies>标签中可以添加如下三个参数就能确定一个依赖的具体信息

<dependency>
<!-- 项目组 -->
<groupId>mysql</groupId>
<!-- 项目名 -->
<artifactId>mysql-connector-java</artifactId>
<!-- 版本号 -->
<version>5.1.47</version>
</dependency>

在idea的pom.xml文件中用快捷键alt + insert可以快速添加本地依赖。

本地没有的话可以在这个网站搜索

依赖配置

添加依赖之后还需要对依赖进行配置,比如确定 依赖范围依赖版本维护等。

Maven中有以下5种典型的依赖范围:

  • compile :编译依赖范围。如果没有指定,默认就是这种依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。
  • test :测试依赖范围。使用此依赖范围的Maven依赖,只对测试classpath有效。在编译主代码和运行项目期间都不需要使用此依赖。典型的例子就是Junit,它只在编译和运行测试代码时有效。
  • provided :已提供依赖范围。使用此依赖范围的maven依赖在编译和测试classpath有效,但运行时无效。典型的例子就是servlet-api。编译和测试的时候需要使用servlet-api中的方法,但是使用tomcat运行项目的时候不需要,因为tomcat在运行期间会提供这个依赖。
  • runtime: 运行时依赖范围。使用次依赖范围的maven依赖对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要提供JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
  • system :系统依赖范围。该依赖与三种classpath的关系和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显式地指定依赖文件的路径。由于此依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能造成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量。

system 类型的依赖有个典型的例子就是oracle的驱动包,从中央仓库无法下载,需要先下载到本地,再通过本地路径引入。

<dependency>
<groupId>oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>1.0</version>
<scope>system</scope>
<!-- 必须指定systemPath -->
<systemPath>D:/software/maven/apache-maven-3.5.2/repository/ojdbc6.jar</systemPath>
</dependency>

依赖范围与classpath的关系如下:

依赖 对于编译classpath有效 对于测试classpath有效 对于运行时classpath有效 例子
compile Y Y Y spring-core
test - Y - Junit
provided Y Y - servlet-api
runtime - Y Y JDBC驱动
system Y Y - 本地的,maven仓库之外的类库

指定依赖的方式很简单,只需在<dependency>标签中使用<scope>设置即可。

示例
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.9.RELEASE</version>
<!--compile是默认的依赖范围,可以不用写出来-->
<scope>compile</scope>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.8</version>
<scope>runtime</scope>
</dependency> <dependency>
<groupId>oracle</groupId>
<artifactId>ojdbc</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>D:/software/maven/apache-maven-3.5.2/repository/ojdbc6.jar</systemPath>
</dependency>

如果pom.xml文件中的依赖太多不便于统一管理,因此可以将版本号抽象出来同一管理:

示例
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
<struts.version>2.3.8</struts.version> <!-- IDEA中输入junit.version自动补全为下面的方式 -->
<junit class="version">4.11</junit>
</properties> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>${struts.version}</version>
</dependency>
</dependencies>

插件

如上面所说,Maven核心并没有什么功能,它的本质就是一个插件框架,所有的功能都是由插件来完成。同时官方提供了一些默认的插件,如果需要配置自己的插件,也可使引入坐标来实现。

官方的插件列表

http://maven.apache.org/plugins/index.html
http://mojo.codehaus.org/plugins.html

一个编译插件的例子:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

清理文件

由于网络原因仓库中可能存在以lastUpdated结尾的文件导致jar包导入失败,用everything搜一下删除就好了。

更新依赖

有时候配置了仓库后找不到jar包,此时需要在idea中更新仓库依赖:setting -> build -> buildTools -> maven -> repositories -> update


具体pom.xml的细节可以百度(。・ω・。)


这里放一个设置maven使用jdk 1.8的设置:

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

最新文章

  1. Goodbye2014,Hello2015
  2. JavaScript电子时钟+倒计时
  3. c c++怎么判断一个字符串中是否含有汉字
  4. MyBatis知多少(9)不同类型的数据库
  5. Gradle学习系列之十——自定义Plugin(本系列完)
  6. Android 手势识别类 ( 二 ) GestureDetector 源码浅析
  7. 封装getElementsByClassName
  8. Windows Media Player安装了却不能播放网页上的视频
  9. IT全称
  10. IOS NSURL基本操作-备
  11. iOS CFStringTransForm汉字转拼音
  12. linux防火墙设置常用命令
  13. Linux&#160;Linux下最大文件描述符设置
  14. 用python设置定时任务
  15. Linux虚拟文件系统
  16. 20145208 蔡野 《网络对抗》Exp8 Web基础
  17. 20165327 2017-2018-2 《Java程序设计》第9周学习总结
  18. Hadoop Version History and Feature
  19. Luogu2661 信息传递(图论)
  20. Zookeeper命令行zkCli.sh&amp;zkServer.sh的使用(四)

热门文章

  1. 初识PromQL
  2. 修饰者模式(装饰者模式,Decoration)
  3. 067、Java面向对象之不实例化对象报错
  4. Docker 镜像文件的导入和导出
  5. WebRobot1.8.2网站多功能网络安全渗透检测工具
  6. Ubuntu18.04 ElasticSearch7.3.2集群搭建(一)
  7. (十)微信小程序---上传图片chooseImage
  8. CCF 201703-4 地铁修建(最小生成树)
  9. mac下添加环境变量
  10. 【capstone/ropgadget】环境配置