02-Maven
1. 什么是Maven
- 目前无论使用IDEA还是Eclipse等其他IDE,都使用ANT工具。ANT工具帮助我们进行编译、打包、运行等工作
- Apache基于ANT进行了升级,研发出了全新的自动化构建工具Maven。Maven是Apache的一款开源的项目管理工具
- 以后无论是普通JavaSE项目还是JavaEE项目,创建的都是Maven项目
- Maven使用项目对象模型(POM-Project Object Model),通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具
- 在Maven中每个项目都相当于是一个对象,对象(项目)和对象(项目)之间是有关系的
- 关系包含了:依赖、继承、聚合,实现Maven项目可以更加方便的实现导jar包、拆分项目等效果
2. Maven下载-目录结构
- IDEA默认自带并整合了Maven
- 在IDEA中可以自定义集成Maven
- 目录结构
bin
:存放的是执行文件,命令conf
:下面有一个非常重要的配置文件 =>settings.xml
=> maven的核心配置文件/全局配置文件
- 如果没有
.m2
目录 ,自己手动执行mvn命令:mvn help:system
3. Maven仓库
- Maven仓库是基于简单文件系统存储的,集中化管理Java API资源(构件)的一个服务
- 仓库中的任何一个构件都有其唯一的坐标,根据这个坐标可以定义其在仓库中的唯一存储路径。得益于Maven的坐标机制,任何Maven项目使用任何一个构件的方式都是完全相同的
- Maven可以在某个位置统一存储所有的Maven项目共享的构件,这个统一的位置就是仓库,项目构建完毕后生成的构件也可以安装、部署到仓库中,供其它项目使用
- 对于Maven来说,仓库分为两类:本地仓库、远程仓库
- 在
settings.xml
中,配置了三个信息:- 本地仓库
- 镜像仓库
- JDK
1. 远程仓库
- 不在本机的一切仓库,都是远程仓库:分为中央仓库、本地私服仓库
- 远程仓库指通过各种协议如
file://
和http://
访问的其它类型的仓库- 第三方搭建的真实的远程仓库,用来提供他们的构件下载(eg:
repo.maven.apache.org
和uk.maven.org
是Maven的中央仓库) - 其它”远程“仓库,可能是公司拥有的建立在文件/HTTP服务器上的内部仓库(不是Apache的中央仓库,而是公司的私服,在局域网搭建的maven仓库),用来在开发团队间共享私有构件和管理发布
- 第三方搭建的真实的远程仓库,用来提供他们的构件下载(eg:
- 默认的远程仓库使用的Apache提供的 中央仓库
2. 本地仓库
本地仓库指本机的一份拷贝,用来缓存远程下载,包含开发尚未发布的临时构件
3. 仓库配置
1. 配置本地仓库
本地仓库是开发者本地电脑中的一个目录,用于缓存从远程仓库下载的构件。默认的本地仓库是${user.home}/.m2/repository
。用户可使用settings.xml
文件修改本地仓库。具体内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<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>具体本地仓库位置</localRepository>
<!-- 省略,具体信息参考后续内容 -->
</settings>
2. 配置镜像仓库
- 如果仓库A可以提供仓库B存储的所有内容,那么就可以认为A是B的一个镜像
- eg:在国内直接连接中央仓库下载依赖,由于一些特殊原因下载速度非常慢
- 使用阿里云提供的镜像
http://maven.aliyun.com/nexus/content/groups/public/
来替换中央仓库http://repol.maven.org/maven2/
。修改maven的setting.xml
- 使用阿里云提供的镜像
<mirror>
<!-- 指定镜像ID(可自己改名) -->
<id>nexus-aliyun</id>
<!-- 匹配中央仓库(阿里云的仓库名称,不可以自己起名,必须这么写)-->
<mirrorOf>central</mirrorOf>
<!-- 指定镜像名称(可自己改名) -->
<name>Nexus aliyun</name>
<!-- 指定镜像路径(镜像地址) -->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
4. 仓库优先级
- 本地仓库
- 镜像仓库
- 中央仓库
4. JDK的配置
- 当idea中有多个JDK时,就需要指定编译和运行的JDK。
settings.xml
中配置 - 配置的前提是你的idea中要有1.8的jdk
<profile>
<!-- settings.xml中的id不能随便起的 -->
<!-- 告诉maven用jdk1.8 -->
<id>jdk-1.8</id>
<!-- 开启JDK的使用 -->
<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>
5. Maven工程类型
POM
工程- POM工程是逻辑工程。用在父级工程或聚合工程中。用来做jar包的版本控制
JAR
工程- 将会打包成jar,用作jar包使用。即常见的本地工程 => Java Project
WAR
工程- 将会打包成war,发布在服务器上的工程
6. IDEA创建Maven工程
过程:
7. Maven项目结构
标准目录结构:
src/main/java
- 这个目录下储存java源代码
src/main/resources
- 储存主要的资源文件。eg:xml配置文件、properties文件
src/test/java
- 储存测试用的类。eg:JUNIT的测试一般就放在这个目录下面
- 因为测试类本身实际是不属于项目的,所以放在任何一个包下都显得很尴尬,所以maven专门创建了一个测试包,用于存放测试的类
src/test/resources
- 需要自己创建,储存测试环境用的资源文件
src
- 包含了项目所有的源代码、资源文件,以及其他项目相关的文件
target
- 编译后内容放置的文件夹
pom.xml
- 是Maven的基础配置文件。配置项目和项目之间关系,包括配置依赖关系等等
结构图:
|-- MavenDemo:项目名
|-- .idea:项目的配置,自动生成的,无需关注
|-- src
|-- main:实际开发内容
|-- java:写包和java代码,此文件默认只编译.java文件
|-- resource:所有配置文件。最终编译把配置文件放入到classpath中
|-- test:测试时使用,自己写测试类或junit工具等
|-- java:储存测试用的类
|-- pom.xml:整个maven项目所有配置内容
注意:目录名字不可以随便改,maven进行编译、jar包生成操作时,是根据这个目录结构进行的
8. POM模式
- Maven工具基于项目对象模型(POM-Project Object Model)实现
- 在Maven中每个项目都相当于是一个对象,对象(项目)和对象(项目)之间是有关系的
- 关系包含了:依赖、继承、聚合,实现Maven项目可以更加方便的实现导jar包、拆分项目等效果
1. 依赖
- 依赖关系
- 即A工程开发、运行过程中需要B工程提供支持,则代表A工程依赖B工程。通俗理解:就是导jar包。B工程可以是自己的项目打包后的jar包,也可以是中央仓库的jar包
- 需要在A项目的
pom.xml
文件中增加下属配置,定义依赖关系
- 如何注入依赖
pom.xml
文件,根元素project下的<dependencies>
标签中,配置依赖信息,其内可以包含多个<dependency>
- 依赖的好处
- 省去了手动添加jar包操作,省事!!
- 解决jar包冲突问题
1. 依赖的传递性
如果B依赖了C,那么A依赖B时,会自动把B和C都导入进来
- 传递性是Maven2.0的新特性。假设项目依赖于一个库,这个库又依赖于其他库。不必去找出所有这些依赖,只需要加上直接依赖的库,Maven会隐式的把直接库中,间接依赖的库也加入到项目中
- 这个特性是靠解析远程仓库中获取的依赖库的项目文件实现的。一般的,这些项目的所有依赖都会加入到项目中,或从父项目继承,或通过传递性依赖
创建A项目后,选择IDEA最右侧Maven面板Lifecycle,双击install
后就会把项目安装到本地仓库中,其他项目就可以通过坐标引用此项目
- 项目1:MavenDemo项目依赖了Mybatis的内容:
- 注意:请将项目1打包为jar包 => 重新打包
- 创建项目2:让项目2依赖项目1:
- 可以证明:项目2依赖项目1,项目1依赖Mybatis工程 => 传递性 => 项目2可以直接使用Mybatis
2. 两个原则
- 第一原则:最短路径优先原则
- 意味着项目依赖关系树中路径最短的版本会被使用
- eg:假设A、B、C之间的依赖关系是
A->B->C->D(2.0)
和A->E->(D1.0)
,那么D(1.0)
会被使用
- 第二原则:最先声明原则
- 依赖路径长度一样时,第一原则不能解决所有问题。eg:
A–>B–>Y(1.0)
、A–>C–>Y(2.0)
,Y(1.0)
和Y(2.0)
的依赖路径长度一样。谁会被解析使用呢?在maven2.0.8及之前的版本中,这是不确定的 - maven2.0.9开始,为了尽可能避免构建的不确定性,maven定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,POM中依赖声明的顺序决定了谁会被解析使用
- 依赖路径长度一样时,第一原则不能解决所有问题。eg:
3. 排除依赖
<exclusion>
:用来排除传递性依赖。标签里面对应的有g, a两项基本元素,不用写版本号。可配置多个<exclusion>
- eg:A -> B -> C (
Mybatis.jar
) 排除C中的Mybatis.jar
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
4. 依赖范围
依赖范围决定了依赖的坐标,在什么情况下有效
- compile
- 默认范围。如果没有指定,就会使用该依赖范围。表示该依赖在编译、运行时都生效
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
<scope>compile</scope>
</dependency>
- provided
- 已提供。典型的例子是servlet-api,编译和测试项目时需要该依赖,但在运行项目时,由于容器已经提供,就不需要Maven重复引入一遍
- runtime
- 表明编译时不需要生效,而只在运行时生效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或运行项目时才需要实现上述接口的具体JDBC驱动
- system
- 与provided类似,不过必须显式指定一个本地系统路径的JAR,此类依赖应该一直有效,Maven也不会去仓库中寻找它
- system范围依赖时必须通过
systemPath
元素显式地指定依赖文件的路径
- test
- 表明只在编译测试代码和运行测试时需要,应用的正常运行不需要此类依赖
- Junit的jar包在测试阶段用就可以了,导出项目时没必要带junit的东西
- Import
- 表明指定的POM必须使用
<dependencyManagement>
部分的依赖 - 注意:import只能用在
<dependencyManagement>
的scope里
- 表明指定的POM必须使用
1. import
- 定义一个父工程 -> POM工程
- 注意:父工程要打成jar包
<groupId>com.msb</groupId>
<artifactId>MavenDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<banben>3.5.4</banben>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${banben}</version>
</dependency>
</dependencies>
</dependencyManagement>
- 定义一个子工程
<relativePath>../MavenDemo/pom.xml</relativePath>
<groupId>com.msb</groupId>
<artifactId>MavenDemo2</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>com.msb</groupId>
<artifactId>MavenDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../MavenDemo/pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies>
- 如果父工程中加入
<scope>import</scope>
,相当于强制指定了子工程的版本号
<groupId>com.msb</groupId>
<artifactId>MavenDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<banben>3.5.4</banben>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${banben}</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. system
- 引入外部jar
<dependency>
<groupId>com.listao</groupId>
<artifactId>fusion-data-trans</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/lib/fusion-data-trans-2023.1.1-RELEASE.jar</systemPath>
</dependency>
build
<targetPath>BOOT-INF/lib/</targetPath>
会将gav_jar
、手动_jar
都放到BOOT-INF/lib
下
<build>
<resources>
<resource>
<directory>${project.basedir}/src/lib</directory>
<targetPath>BOOT-INF/ooxx/</targetPath>
</resource>
</resources>
</build>
<resources>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/**</include>
</includes>
</resource>
<!-- 打包成jar静态资源必须指明路径,打包成war可以不用 -->
<resource>
<directory>${basedir}/src/main/webapp</directory>
<targetPath>META-INF/resources/</targetPath>
<includes>
<include>**/**</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/**</include>
</includes>
<filtering>false</filtering>
<!--<filtering>true</filtering>-->
<!--<excludes>-->
<!-- <exclude>rebel.xml</exclude>-->
<!--</excludes>-->
</resource>
</resources>
</build>
2. 继承
- 本质上:POM文件的继承
- 如果A工程继承B工程,则代表A默认依赖B依赖的所有资源,且可以应用B中定义的所有资源信息
- 被继承的工程(B工程)只能是POM工程
- 父项目中
<dependencyManagement>
- 不被子项目继承,不可以直接使用
- 主要目的是进行版本管理。里面的内容在子项目中依赖时坐标只需要填写
<groupId>
和<artifactId>
- 子项目不希望使用父项目控制的版本,可以明确配置
<version>
- 父工程是一个POM工程
- 创建子工程
3. 聚合
- 当开发的工程拥有2个以上模块时,每个模块都是一个独立的功能集合。都可以独立编译、测试、运行。就需要一个聚合工程
- eg:某大学系统中拥有搜索平台,学习平台,考试平台等
- 创建聚合工程的过程中,总的工程必须是一个POM工程(Maven Project)(聚合项目必须是一个pom类型的项目,jar、war项目是没有办法做聚合工程的)
- 各子模块可以是任意类型模块(Maven Module)
- 聚合包含了继承的特性
- 聚合时多个项目的本质还是一个项目。这些项目被一个大的父项目包含。且父项目为pom类型,同时
pom.xml
中出现<modules>
表示包含的所有子模块
- 总项目:
<packaging>pom</packaging>
<modelVersion>4.0.0</modelVersion>
<groupId>com.msb</groupId>
<artifactId>ParentPro</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>ChildPro</module>
</modules>
<!-- 定义为pom项目 -->
<packaging>pom</packaging>
<!-- 定义版本号 -->
<properties>
<mybatis.version>3.5.4</mybatis.version>
<spring.version>5.1.11.RELEASE</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
- 具体模块
<parent>
<artifactId>ParentPro</artifactId>
<groupId>com.msb</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ChildPro</artifactId>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
</dependencies>
9. 常见插件
1. 编译器插件
通过编译器插件,可以配置使用具体JDK版本
settings.xml
文件中配置全局编译器插件
<profile>
<!-- 定义的编译器插件ID,全局唯一,名字随便起 -->
<id>jdk-1.7</id>
<!-- 插件标记,activeByDefault: true默认编译器,jdk提供编译器版本 -->
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.7</jdk>
</activation>
<!-- 配置信息source-源信息,target-字节码信息,compilerVersion-编译过程版本 -->
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.compilerVersion>1.7</m aven.compiler.compilerVersion>
</properties>
</profile>
- 配置当前项目编译器插件:
pom.xml
- JDK1.7不支持
interface
中的非抽象方法
- JDK1.7不支持
public interface TestInf {
default void eat() {
}
}
<!-- 配置maven的编译插件 -->
<build>
<plugins>
<!-- JDK编译插件 -->
<plugin>
<!-- 插件坐标 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<!-- 源代码使用JDK版本 -->
<source>1.7</source>
<!-- 源代码编译为class文件的版本,保持跟上面版本一致 -->
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2. 资源拷贝插件
- Maven在打包时,默认只将
src/main/resources
里的配置文件,拷贝到项目中并做打包处理,而非resource
目录下的配置文件在打包时不会添加到项目中 - 打包后配置文件就会在
target/classes
下面放着
- 把非
resources
下面的文件也打包到classes下面:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
- 配置好以后,那么你设置的位置下的配置文件都会被打包了:
3. Tomcat插件
创建war项目,必然要部署在服务器上,方式:
- 部署在远程服务器上
- 将IDEA和外部tomcat产生关联,然后将项目部署在外部tomcat上
- 不再依赖外部的tomcat,maven提供了tomcat插件,配置来使用
在index.jsp
中随便写点东西:
- 使用Tomcat插件发布部署并执行war工程时,需要使用启动命令:
tomcat7:run
- 命令中的tomcat7是插件命名,由插件提供商决定
- run为插件中的具体功能
- (注意:之前的编译器插件、资源拷贝插件,不是可运行的插件。Tomcat属于可运行插件,它什么时候工作需要程序员来控制,必须通过命令来运行控制)
具体pom.xml
文件的配置如下:
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 配置Tomcat监听端口 -->
<port>8080</port>
<!-- 配置项目的访问路径(Application Context) -->
<path>/</path>
</configuration>
</plugin>
</plugins>
- 执行命令
- 显示Tomcat启动成功
- 在浏览器中访问
index.jsp
页面:
10. Maven常用命令
clean
- 清除已编译信息
- 删除工程中的
target
目录
compile
- 只编译。
javac
命令
- 只编译。
package
- 打包。包含编译,打包两个功能
install
- 本地安装。包含编译、打包、安装到本地仓库
- 编译 -
javac
- 打包 -
jar
, 将java代码打包为jar文件 - 安装到本地仓库 - 将打包的jar文件,保存到本地仓库目录中