1.Maven介绍
Maven是一个基于项目对象模型(POM)的概念的纯java开发的开源的项目管理工具。主要用来管理java项目,进行依赖管理(jar包管理,能自动分析项目所需的依赖软件包,并到Maven仓库区下载)和项目构建(项目编译、打包、测试、部署)。此外还能分块开发,提高开发效率。
2.Maven下载
http://maven.apache.org/download.cgi
3. Maven安装
3.1 解压
注意: 解压文件尽量不要放在含有中文或者特殊字符的目录下。
解压后,有如下目录:
bin:含有mvn运行的脚本
boot:含有plexus-classworlds类加载器框架,Maven 使用该框架加载自己的类库。
conf:含有settings.xml配置文件
lib:含有Maven运行时所需要的java类库
3.2 环境变量
maven依赖java环境,所以要确保java环境已配置好 (maven-3.3+ 需要jdk7+)
maven本身有2个环境变量要配置:
MAVEN_HOME = maven的安装目录
PATH = maven的安装目录下的bin目录
3.3 测试
查看maven版本信息:mvn -v
4.Maven的配置
maven的conf目录下,有maven的配置文件
settings.xml
添加<localRepository>
配置maven的 "本地仓库" 位置,用于存放项目中的相关依赖(比如 所有jar
)
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>D:\Program Files\maven\myrepository</localRepository>
在
<profiles>
标签中 增加 一个<profile>
标签,限定maven项目默认的jdk版本.
内容如下:
<profiles>
<!-- 在已有的profiles标签中添加profile标签 -->
<profile>
<id>myjdk</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
<!-- 让增加的 profile生效 -->
<activeProfiles>
<activeProfile>myjdk</activeProfile>
</activeProfiles>
5.仓库
讲完了maven的基本配置,我们来介绍一下仓库的概念
Maven 仓库
在 Maven 的术语中,仓库是一个位置
(place)。
Maven 仓库是项目中依赖的第三方库,这个库所在的位置叫做仓库
。
在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件
。
Maven 仓库能帮助我们存储、管理构件的地方。
操作模式:开发人员定义简单的配置,描述需要哪些依赖,maven自动从仓库中下载依赖(jar).
5.1 仓库分类
5.2本地仓库
1.在安装 Maven 后并不会创建,第一次执行 maven 命令时才创建。
2.Maven 所需要的构件都是直接从本地仓库获取的。
如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。
3.默认情况下,不管Linux还是 Windows,每个用户在自己的用户目录下都有一个路径名为
.m2/respository/
的本地仓库目录。可以在setttings.xml中修改。
5.3 远程仓库
5.3.1中央仓库
Maven 中央仓库是由 Maven 社区提供的仓库,
其中包含了绝大多数流行的开源Java构件。是默认的远程仓库。(网站在国外,网速杠杠的,绝对超过5kb/s)
https://mvnrepository.com/ 可以搜索需要的依赖的相关信息(仓库搜索服务)
http://repo.maven.apache.org/maven2/ 中央仓库地址
5.3.2 远程仓库(自建的远程仓库)
如果 Maven 在中央仓库中也找不到依赖的文件,它会停止构建过程并输出错误信息到控制台。 为避免这种情况,Maven 提供了远程仓库的概念,它是开发人员自己定制仓库。 比如aliyun仓库(http://maven.aliyun.com/nexus/content/groups/public/)
(我用阿里云主要是因为它快,毕竟是国内的网站,但我搜索一般上mvn官网搜索,阿里云的搜索就是渣啊~~~~)
6. idea中使用Maven
6.1 在idea中关联maven
6.2创建一个Maven项目
6.2.1 选择骨架
骨架中包含一些初始化的项目结构
6.2.2 指定项目名称
6.2.3 设置Maven
6.2.4项目位置
6.2.5 项目结构
1> src/main/java 存放源代码,建包,放项目中代码(service,dao,User,....)
2> src/main/resources 书写配置文件,项目中的配置文件(jdbc.properties)
3> src/test/java 书写测试代码,项目中测试案例代码
4> src/test/resources 书写测试案例相关配置文件
5> 项目根/pom.xml (project object model) maven项目核心文件,其中定义项目构建方式(war包,jar包,默认为jar包,web项目用war包),声明依赖等
注意:项目中的建包,建类,执行,都和普通项目无差异
6.3 导入依赖jar
建好项目后,需要导入需要的jar,要通过【坐标】(GAV)
1. 每个构件都有自己的坐标(标识) = groupId + artifactId + version = 项目标识 + 项目名 + 版本
2. 在maven项目中只需要配置坐标,maven便会自动加载对应依赖。删除坐标则会移除依赖
3. jar包并不会导入到项目目录中,只是maven帮助做了关联。但在打包部署项目时会携带对应依赖
4. 而且,如果导入了依赖A,而A中又依赖了B,则B会被自动加载。
6.3.1 依赖的查找
依赖查找服务:https://mvnrepository.com/ ,获得依赖的坐标,在maven项目中导入。(个人推荐每个人都准备个个人依赖库,打好注解方便使用)
1.mvn官网搜索
2.进入依赖详情页
6.3.2 导入依赖
在项目的pom文件中
6.3.3 同步依赖
引入坐标(GAV)之后同步依赖,确认导入
6.3.4 依赖生命周期
项目中导入的依赖可以做生命周期的管理
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<!-- 生命周期 -->
<scope>compile</scope>
</dependency>
**maven有生命周期如下:
1compile
:缺省值,适用于所有阶段(测试,编译,运行,打包),会随着项目一起发布(被打包)
2provided
:类似compile,期望JDK、容器或使用者会提供这个依赖。如servlet.jar参与测试,编译,不会被打包
3runtime
:只在运行时使用,如 jdbc6.jar,适用运行和测试阶段,会被一起发布
4test
:只在测试时使用,用于编译和运行测试代码,如 junit.jar,不会随项目发布
5system
:类似provided,但Maven不会在Repository中查找它,要在本地磁盘目录中查找,参与编译,测试,打包,运行。
6.4 创建Web项目
6.4.1 选择web骨架
6.4.2 定义项目坐标
6.4.3 选择maven
6.4.4 选择项目磁盘位置
6.4.5 maven-web项目结构
6.4.6 导入依赖
maven-web项目中没有携带servlet相关的依赖,所以需要导入。
否则,servlet相关的组件不能使用,jsp也不能使用
7. idea-tomcat
7.1 编辑运行环境
7.2 新增tomcat-server
7.3 选择tomcat位置
7.4 tomcat细节
8. 部署web项目
8.1 新增部署
8.2 增加artifacts
如下,项目部署有两种选择:war和war-exploded
war
:将项目实际部署到tomcat的web-apps目录中.
war-exploded
:并不会真正部署到tomcat的web-apps目录,tomcat直接访问项目内容(我们选这个)
8.3 设置访问路径
8.4 启动tomcat
9.Aliyun仓库(必需)
中央仓库在国外,下载速度很慢,国内的aliyun仓库是一款很优秀的maven仓库。强烈建议使用
在setting.xml文件中配置如下信息
<mirrors>
<mirror>
<id>aliyun</id>
<!-- 中心仓库的 mirror(镜像) -->
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<!-- aliyun仓库地址 以后所有要指向中心仓库的请求,都由aliyun仓库接替-->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
10.maven特性
10.1 传递性
10.1 传递性
所谓传递性,是指,在项目中导入了依赖A,而A内部依赖了B,则A会自动触发B也被导入项目
好处:没必要导入所有依赖在项目中,传递性会自动导入一些依赖。简化依赖导入管理
坏处:jar冲突
10.1.1 jar冲突
<!-- 冲突示例 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
jar冲突:A依赖B B依赖C和d-1.0 c依赖d-2.0。则此时导入A依赖,那么项目中会采用d-1.0 还是 d-2.0?
maven默认的选择原则是“最短路径”
:
1 d-1.0的路径 A->B->d-1.0
2 d-2.0的路径 A->B->C->d-2.0 则最终选择的是d-1.0 ( 如果路径等长,则先声明的优先 )
解决方案
默认的选择原则明显是不能符合实际的需求的,所以有其他设置可以改变默认原则
1> 排除原则:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
<exclusions>
<!-- 排除一个依赖,则此依赖不会被spring-context-suport传递导入 -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
2> 明确定义:直接定义<dependency>
,则根据最短路径,设置明确版本
3> 在父项目中定义,则子项目中在传递依赖时会以父项目中的声明为准。
10.1.2 传递依赖范围
前置概念:
项目A中 依赖 B库 ,B库 依赖C库;
则A对B是第一直接依赖
,B对C是第二直接依赖
,A对C是传递性依赖
。
如果第一直接依赖范围是:compile,第二直接依赖范围:compile,则传递性依赖范围就是:compile
则,传递性依赖
的范围取决于第一和第二直接依赖
。
compile ( 测、编、运) | runtime( 测、运) | provide( 测,编) | test( 测 ) | |
---|---|---|---|---|
complie | compile | runtime | - | - |
runtime | runtime | runtime | - | - |
provide | provide | provide | provide | - |
test | test | test | - | - |
如上表格:第一列是第一直接依赖范围,第一行是第二直接依赖,交叉的格子是传递性依赖范围。
解释第一行:第一compile,第二compile,则传递compile;
第二runtime,则传递runtime; (B运行时需要C,所以A也要保证运行时有C)
第二provide,则不加载传递依赖;( A不需要测试B,也不需要编译B,所以不需要C)
第二test,则不加载穿刺依赖;(A不需要测试B,所以不需要C)
其他行,也是同样的逻辑关系。
结论:A依赖B,B依赖C ==> A中不一定会加载C;即使加载C,C的scope也会有变动。
10.2 继承
- 多个maven项目间难免有重复的pom配置,重复的配置没必要重复写,maven提供了pom的父子集成机制,类似java的父子类。将共用的pom配置定义在父pom中,自pom继承后就等价持有了父pom中的内容。实现pom复用。
- 项目中的诸多依赖,需要统一管理版本,不建议每个开发者随意指定版本。可以在父项目中声明版本信息,子项目延用即可
10.2.1 定义父项目
定义空白的maven项目(不用写任何代码,只用他的pom文件)
注意:子项目中如果明确定义了版本,则父项目中的声明会失效。所以父项目中声明的版本,子项目中不允许再定义。
10.2.2 子项目继承
子项目pom中继承父pom
10.3 聚合
一个项目(
project
),可以分为多个模块(module
),使得项目更加层次清晰,利于管理。利于模块复用。
模块的划分,常用的方式之一:
基于MVC划分模块
,进一步树立项目层次,对于大型项目尤为实用。
每个模块都是一个单独的maven项目,由一个父项目来做聚合。
模块之间可以互相依赖。
对父项目做编译,清理,打包等行为会传播给所有模块。
10.3.1 创建父模块
可以基于 “quick-start”骨架建立项目,或建立一个空白项目均可。
父模块必须是pom打包!!,其他没特殊要求。
10.3.2 创建子模块
父模块作为:Project,再建项目作为:Module
注意:dao和service模块打包格式为jar,web模块打包格式为war
-
在父模块上 "右键", 为其新建 Module
2. Module的创建,选择骨架时,按需选择即可;如下填写Module的项目名即可
3. 创建完毕后,如下
4. 重复如上过程,再多创建几个Module
5. 父项目的pom,已经发生了改变,<moludels>
标签即在做多模块聚合
10.3.3 父项目中定义版本管理
<!-- 共用的依赖定义 -->
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
....
</dependencies>
<!-- 依赖版本统一管理 -->
<dependencyManagement>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
....
</dependencyManagement>
-
统一管理:
- 如上可以避免在每个子模块中都声明版本号,这样想升级或者切换到另一个版本时,只需要在父模块里更新,不需要任何一个子模块的修改;
-
自定义:
- 如果某个子模块需要另外一个版本号时,只需要在dependencies中声明一个版本号即可。子模块就会使用子模块声明的版本号,不继承于父模块版本号。
在做依赖管理时,也有时会在父项目中不做依赖管理,而是明确导入所有依赖,子模块直接继承后就拥有哪些依赖。service模块只需要单独导入dao,web模块只需要单独导入service。
10.3.4 子模块中定义内容
各个模块中,分别定义对应的依赖、代码、配置。
子模块中需要的配置文件,可以由子模块持有,也可以统一交给web模块持有。
来自不同模块的组件间的注入,编码不变。
dao模块,定义所有DAO。其中的pojo
也可以分为一个单独的模块。
service模块,定义所有Service类。需要导入dao模块,进而注入其中的DAO组件
web模块,定义所有的Controller类,需要导入service模块(同上)
10.3.5 测试
如果dao模块自己持有配置,则可以在dao模块进行测试。反之可以将dao模块导入到web模块,在web模块中测试dao。
Service测试同理。
web模块的测试,可以直接将web模块部署到tomcat即可测试。
10.3.6 部署
在父模块所在目录下,直接执行:
mvn package
, 即可完成所有模块的打包,且web模块的war包中会包含dao,service,pojo模块的jar。
直接部署web模块的war即可。
10.3.7 相关指令
- 测试,对父模块做 打包操作
mvn package - 测试,对父模块做 清理并编译
mvn clean compile - 测试,对父模块做 清理并打包
mvn clean package - 注意:对父模块做的操作都会同步到每个模块上。
11. 私服
私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件。
有了私服之后,当 Maven 需要下载构件时,直接请求私服,私服上存在则下载到本地仓库;否则,私服请求外部的远程仓库,将构件下载到私服,再提供给本地仓库下载。
私服可以解决在企业做开发时每次需要的jar包都要在中心仓库下载,且每次下载完只能被自己使用,不能被其他开发人员使用
所谓私服就是一个服务器,但是不是本地层面的,是公司层面的,公司中所有的开发人员都在使用同一个私服
我们可以使用专门的 Maven 仓库管理软件来搭建私服,比如:Apache Archiva,Artifactory,Sonatype Nexus。这里我们使用
Sonatype Nexus
11.1 Nexus安装
- 下载nexus-2.x-bundle.zip,解压即可
- 解压后在bin目录中执行:
nexus install
在系统中安装nexus服务
nexus uninstall
卸载nexus服务
nexus start
启动服务
nexus stop
停止服务 - 访问私服:http://localhost:8081/nexus/
-
登录私服:admin/admin123
11.2 Nexus登录
11.3 仓库列表
group:包含多个仓库,通过group库的地址可以从包含的多个仓库中查找构件 hosted: 私服 服务器本地的仓库,其中存储诸多构件。 3rd 存放中央仓库没有的 ,如ojdbc.jar,可以上传到私服的该库中。 Releases 存放项目的稳定发布版本,一个模块做完后如果需要共享给他人,可以上传到私服的该库。 Snapshots 对应不稳定的发布版本 proxy:代理仓库,其会关联一个远程仓库, 比如中央仓库,aliyun仓库,向该仓库查找构件时,如果没有会从其关联的仓库中下载。 |
---|
11.4 导入第三方jar到私服
有些jar在中心库中是没有的,比如oracle的数据库驱动jar:ojdb6.jar. 可以自己下载jar,然后上传到私服中。
此种构件,我们建议放在 "3rd party" 仓库中 ( 存放第三方构件 )
11.5 maven配置私服
在maven中配置私服,使得maven可以从私服上获取构件
11.5.1 仓库组
而此时就有问题,私服中有很多仓库,每个仓库都有自己的url,则项目中配置哪个仓库呢 ?
私服中有一个仓库组,组中包含多个仓库,可以指定仓库组的url,即可从多个仓库中获取构件
11.5.2 maven关联私服
配置settings.xml,设置私服地址、认证等信息
配置私服 username/password
More Actions配置私服为maven的远程仓库,注意:【此处的repository的id要和 上图中server的id保持一致,才可以在私服认证通过】
More Actions使profile配置生效
至此,maven项目中需要依赖时,maven会从私服中下载
11.6 maven项目部署到私服
在项目的pom中配置部署仓库位置:
执行 :mvn deploy
即可将项目部署到私服对应的仓库中,此时项目中的打包方式多为jar
注意:如上的repository
的id
依然是要和settings.xml中配置的server
中的id
对应才能通过私服的认证
12. mave常用指令
mvn compile 编译
mvn clean 清除上次编译的内容
mvn clean compile 清除并编译
mvn package 打包
13. Resources
Resources插件,负责将配置文件复制到编译目录中。两种配置文件,main-resources、test-resources
Maven默认只关注 resources目录下的配置文件,其他目录下的配置文件会被忽略。
13.1 增加资源目录
如果有配置文件不在 resources目录下,则需要额外配置:
<build>
<resources>
<!-- src/main/java目录也是一个资源目录,其中的配置文件也会被复制到编译目录 -->
<resource>
<directory>src/main/java</directory>
</resource>
</resources>
</build>
13.2 排除或包含
如果有资源目录中有需要排除的配置文件,可以如下设置:
<resource>
<directory>src/main/java</directory>
<!--**代表src/main/java下的子目录或子目录的子目录..
*.txt 代表所有txt文件。
所有文件可以用:*.* 或 *
【排除所有txt文件,其他文件都会被复制】
-->
<excludes>
<exclude>**/*.txt</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/java</directory>
<!--**代表src/main/java下的子目录或子目录的子目录..
*.txt 代表所有txt文件。
所有文件可以用:*.* 或 *
【复制所有txt文件,其他文件都会被忽略】
-->
<includes>
<include>**/*.txt</include>
</includes>
</resource>