Maven总结
Maven实战
Maven的指令
Maven clean 删除掉编译的结果,也就是target目录下的classes的文件们
Maven compile 进行编译,可以用来判断依赖是不是有问题的。
Maven test 编译并且执行测试方法
Maven package将当前目录的项目进行打包并且生成到target中一个jar包
Maven install 打包并且安装到本地的仓库中
<dependency>
<groupId></groupId> 公司名称
<artifactId></artifactId> 项目名称
<version></version> 版本号码
</dependency>
Mvn dependency:tree > tree.txt
Mvn dependency:tree > ./tree.txt
这两种的效果一样,都表示在当前目录下面创建依赖树。
使用指令创建一个maven项目
Mvn archetype:generate
idea中无法识别maven
问题描述:
maven在idea启动之后似乎没有用,报如下错误
然后根据提示去查找logs,在idea的help的show log in explorer上查看log
https://blog.csdn.net/aguda_king/article/details/72550673?locationNum=7&fps=1
定位到的一个异常是如下所示:
Caused by: java.rmi.RemoteException: Cannot start maven service; nested exception is:
com.intellij.execution.ExecutionException:
在stackoverflow中查到:
https://stackoverflow.com/questions/26754344/intellij-cannot-start-maven-service-executionexception
原来是jdk的设置是异常的。
解决方式如下:
I had this problem all of a sudden (after an update + Windows Update). I tried a lot of things, and in the end, set Settings > Build, Execution, Deployment > Build Tools > Maven > Importing > JDK for Importer to Use JAVA_HOME (which I've set up as an env var pointing to a JDK install). That seems to work.
编译不通过常见问题
版本没指定
<version>1.2.28</version>
父模块中一般定义了一个版本号码
而且一般情况下找不到某个类的问题一般都是因为没有加版本号码
可以通过mvn compile编译判断maven依赖有没有通过。
依赖树排包
===如何从import中开始判断某个包到底使用了哪个依赖dependency
mvn dependency:tree >./tree.txt
其中./表示的就是当前目录
===如何根据一个包的全限定名找到某个包的依赖呢?
使用依赖树去进行查找
父模块中新建一个子模块
重新创建一个模块
https://blog.csdn.net/yangfanj/article/details/73497803
我要新建的哪个模块的content root最后需要加一个\,让目录生成到最后
Maven依赖
Maven依赖通过groupId,ArtifactId,version三个参数像坐标一样唯一定位一个依赖。当我需要其他依赖的时候直接通过坐标引入就可以了。
当前项目依赖
为当前的模块定义一个坐标,包名尽量是和groupId和artificialID结合的,这是一个模块的pom的编写。
包名可以是com.juvenxu.mvnbook.helloworld
引入其他依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
打包main方法jar
为了让打包之后的jar文件有个可以直接执行的入口main方法需要一个插件的帮助。
被<build></build>以及<plugins></plugins>包裹
执行mvn clean install
最后直接执行就可以了
java -jar buptyhw.study.maven-1.0-SNAPSHOT.jar
依赖范围<scope>
依赖范围是用来控制依赖和类路径之间的关系,其中类路径有三种:编译类路径classpath,测试类路径,运行类路径)可以通过scope来进行控制maven有以下几种依赖的范围:
其中
Provided的例子就是servlet-api,因为运行的时候容器本身就提供了,那么maven本身就不需要提供了。
Runtime运行范围依赖,运行时依赖。典型的就是JDBC驱动,因为编译的时候只需要接口,只有在测试和具体运行的时候才需要实现具体的jdbc驱动。
System系统范围依赖,需要制定路径,因为使用的是maven仓库之外的依赖。
排除依赖<exclusion>
<exclusions>
<exclusion></exclusion>
</exclusions>
排除标签
传递依赖
A依赖于B,B依赖于C,那么A传递依赖于C
***传递性依赖的依赖范围?
第一列表示第一直接依赖的范围,第一行表示第二直接依赖的范围。
依赖的先后
依赖先后第一由深度决定。
1. 按照深度,深度越短先依赖谁。
2. 深度相同,按照声明先后进行依赖。
可选依赖<optional>不会传递
可选的依赖不会传递,只会对当前的项目产生作用。
应用就是:某个持久层的隔离工具包,根据不同的数据库有不同的驱动程序,这个时候就要依赖不同的数据库驱动依赖。
<Properties>标签使用
可以定义properties的属性值
1 <properties>
2 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3 <junit.version>4.9</junit.version>
4 <maven.version>0.0.1-SNAPSHOT</maven.version>
5 </properties>
然后通过访问属性的方式进行访问${junit.version}
1 <dependency>
2 <groupId>junit</groupId>
3 <artifactId>junit</artifactId>
4 <version>${junit.version}</version>
5 <scope>test</scope>
6 </dependency>
聚合(父子模块)<parent>
聚合模块其实就是父模块,至于说为什么需要一个父模块,为了是能够输一次指令就将所有模块都构建完成(快速构建项目),而不需要每个模块都输一次指令。
聚合模块中:packaging必须为pom
聚合模块中:
packaging必须为pom
name字段只是提供一个容易阅读的名字
继承<dependencyManagement>
继承的目的就是抽取出模块中相同的依赖,避免重复配置。
插件和依赖都能够进行继承。
使用<dependencyManagement>来包裹父子类公共的依赖,但是在父模块中声明的依赖并不会给父模块以及子模块真正的引入依赖,而是说子模块能够继承父模块的依赖!!!!
在子模块需要使用继承的依赖的时候,还是需要进行声明的,只是不需要声明版本号码了。
1 <dependencyManagement>
2 <dependencies>
3 <dependency>
4 <groupId>junit</groupId>
5 <artifactId>junit</artifactId>
6 <version>${junit.version}</version>
7 <scope>test</scope>
8 </dependency>
9 <dependency>
10 <groupId>cn.itcast.maven</groupId>
11 <artifactId>HelloFriend</artifactId>
12 <version>${maven.version}</version>
13 <type>jar</type>
14 <scope>compile</scope>
15 </dependency>
16 </dependencies>
17 </dependencyManagement>
聚合与继承的实例
① 父pom.xml:
<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.itmuch.maven</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<url>http://maven.apache.org</url>
<modules>
<!-- 被聚合的项目的路径 -->
<module>../maven-dao</module>
<module>../maven-service</module>
</modules>
<!-- 定义properties,可使用${名称}来调用,例如:${junit.version} -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.10</junit.version>
</properties>
<!-- 使用dependencyManagement,可对依赖进行管理。子类只要不引用这个里面写的groupId + artifactId,则不会添加依赖,这样防止造成重复加了包:如果不使用dependencyManagement,那么只要写了dependency,子pom中会全部添加到依赖中,而其中很多包可能都用不上 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 聚合其他项目 -->
<modules>
<module>../maven-dao</module>
<module>../maven-service</module>
</modules>
</project>
② 子pom.xml:
<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>
<!-- 指定parent,说明是从哪个pom继承 -->
<parent>
<groupId>com.itmuch.maven</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 指定相对路径 -->
<relativePath>../maven-parent</relativePath>
</parent>
<artifactId>maven-dao</artifactId>
<name>maven-dao</name>
<!-- 只需要指明groupId + artifactId,就可以到父pom找到了,无需指明版本 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
配置文件<setting.xml>
***配置文件Setting.xml
maven的全局配置文件,一般放在~/.m2/目录下,~表示用户目录。从安装目录的conf中复制过来。
一般修改用户目录下的,全局的那个是会影响所有用户的。
Maven生命周期与插件
项目构建
***什么是项目构建生命周期,有哪些流程?
生命周期的每个步骤是插件来做。
生命周期详解
Maven生命周期就是为了对所有的构建过程进行抽象和统一,包括项目清理,初始化,编译,打包,测试,部署等几乎所有构建步骤。
Maven有三套相互独立的生命周期,请注意这里说的是"三套",而且"相互独立",这三套生命周期分别是:
- Clean Lifecycle 清理工作。
- Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。
- Site Lifecycle 生成项目报告,站点,发布站点。
每一套生命周期中有很多的阶段,而且运行任何一个阶段的时候,它前面的所有阶段都会被运行,这也就是为什么我们运行mvn install 的时候,代码会被编译,测试,打包。此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要。
① clean
1) pre-clean 执行一些需要在clean之前完成的工作
2) clean 移除所有上一次构建生成的文件
3) post-clean 执行一些需要在clean之后立刻完成的工作
② compile
1)validate
2)generate-sources
3)process-sources
4)generate-resources
5)process-resources 复制并处理资源文件,至目标目录,准备打包。
6)compile 编译项目的源代码。
7)process-classes
8)generate-test-sources
9)process-test-sources
10)generate-test-resources
11)process-test-resources 复制并处理资源文件,至目标测试目录。
12)test-compile 编译测试源代码。
13)process-test-classes
14)test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。
15)prepare-package
16)package 接受编译好的代码,打包成可发布的格式,如 JAR 。
17)pre-integration-test
18)integration-test
19)post-integration-test
20)verify
21)install 将包安装至本地仓库,以让其它项目依赖。
22)deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享。
③ site
1)pre-site 执行一些需要在生成站点文档之前完成的工作
2)site 生成项目的站点文档
3)post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
4)site-deploy 将生成的站点文档部署到特定的服务器上
Maven做测试的方式
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
public class HelloWorldTest {
@Test
public
void testHelloWorld() {
HelloWorld helloWorld = new HelloWorld();
System.out.println(helloWorld.hello());
}
}
可以看到测试类名以Test结尾,方法以test开头。
执行 mvn clean test自动会执行测试
所以类的命名必须以Test打头或者结尾。
Maven版本管理
版本管理:总版本号.分支版本号.小版本号-里程碑版本
① 总版本号的变动,一般表示框架的变动
② 分支版本号:一般表示增加了一些功能
③ 小版本号:一般表示在分支版本的基础上进行了一些bug的修复
④ 里程碑版本号:SNAPSHOT --> alpha(内部测试版本) --> beta(公测版本) --> realese --> GA
一个项目发布一般包含各个版本的变迁。
主干和分支和标签
主干,分支和版本之间的关系。
Snapshot版本与Release版本
1. Snapshot版本代表不稳定、尚处于开发中的版本
2. Release版本则代表稳定的版本
3. 什么情况下该用SNAPSHOT?
协同开发时,如果A依赖构件B,由于B会更新,B应该使用SNAPSHOT来标识自己。这种做法的必要性可以反证如下:
a.如果B不用SNAPSHOT,而是每次更新后都使用一个稳定的版本,那版本号就会升得太快,每天一升甚至每个小时一升,这就是对版本号的滥用。
b.如果B不用SNAPSHOT, 但一直使用一个单一的Release版本号,那当B更新后,A可能并不会接受到更新。因为A所使用的repository一般不会频繁更新release版本的缓存(即本地repository),所以B以不换版本号的方式更新后,A在拿B时发现本地已有这个版本,就不会去远程Repository下载最新的B
4. 不用Release版本,在所有地方都用SNAPSHOT版本行不行?
不行。正式环境中不得使用snapshot版本的库。
比如说,今天你依赖某个snapshot版本的第三方库成功构建了自己的应用,明天再构建时可能就会失败,因为今晚第三方可能已经更新了它的snapshot库。你再次构建时,Maven会去远程repository下载snapshot的最新版本,你构建时用的库就是新的jar文件了,这时正确性就很难保证了。
Maven仓库
私有仓库
为什么需要私有仓库,因为一直使用中心仓库速度会很慢,所以使用私有仓库提升速度。
在settings.xml中配置仓库:
远程仓库的设置
远程仓库可以设置更新频率
<repositories>的设置,可以设置多个远程仓库。
<snapshots>中可以指定下不下载发布版的或者快照版的构件。
远程仓库还可以设置更新的频率,如下可以判断:
远程中央仓库配置实例
中央工厂:maven/lib/maven-model-build.jar中的maven-model-builder-3.2.1.jar中:
org\apache\maven\model\pom-4.0.0.xml配置的
<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>
远程仓库的密码认证
对远程仓库进行认证设置,也就是写账号和密码
部署到远程仓库
在父模块的Pom中设定