概念
Maven的产生的目的是为了解决项目中依赖的管理,以及为项目的构建指定了新的规范
相关的依赖都存放在Maven的中央仓库中,那么怎么才能快速的定位到相关资源的存放位置呢?所以关于maven的资源定位有以下几个需要注意的概念:
-
groupId
组织id,例如:
com.apache..
-
artifactId
项目id,常见是项目的名称
-
version
项目的版本号,常见的:
release(发布版)
和snapshot(开发版)
-
packaging(非必须)
打包方式
安装Maven
这里仅简单的介绍描述安装Maven的过程
- 下载:到apache maven的官网中下载相关的安装包(官网地址)
- 配置:maven是免安装的,下载后只需要配置环境变量
maven_home
,注意配置依赖于Java_home
- 验证:在命令行界面执行
mvn
相关的命令即可
两个常用的maven相关的网址:
- 官方下载地址:https://maven.apache.org/download.cgi
- 查询相关依赖:https://mvnrepository.com/
中央仓库、私服、本地仓库
当项目需要依赖时,首先会在本地仓库寻找,其次会去远程仓库拉取
setting配置文件
-
指定本地仓库存放的位置
<!-- 在配置文件中寻找该配置 --> <localRepository>E:\apache-maven-3.8.4\repository</localRepository>
-
设置替换中央仓库的镜像
<!-- 设置aliyun的maven镜像 --> <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
-
指定私服
mvn
常用命令行
-
清除:clean
清除编译后产生的文件
-
编译:compile
编译项目的相关文件
-
测试:test
执行单元测试
-
打包:package
生成相应的jar文件
-
安装:install
将项目打包,并生成到maven的本地仓库中
IDEA创建maven项目
创建Java项目
步骤
- 创建empty project
- 在empty project中添加module,并且module的类型选择maven即可,其中的目录结构如图上2所示
- 给文件夹指定相应的类型
创建Java web项目
创建的步骤与上一步相同,不同的是选择了maven
下的webapp
的模板进行创建,在webapp
可以引用tomcat7
插件进行启动,否则也可以将war
包放入本地tomcat
容器中
相关配置如下:
<build>
<plugins>
<plugin>
<!--指定了tomcat容器插件-->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<uriEncoding>utf-8</uriEncoding>
<port>80</port>
<url>/</url>
</configuration>
</plugin>
</plugins>
</build>
pom.xml
的配置详解
对于单个项目的配置文件大致可以分为以下这些,针对多个项目,多个模块要一起管理的,则还会有其他的配置项
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!--maven pom的模型版本,不需要修改-->
<modelVersion>4.0.0</modelVersion>
<!--组织id-->
<groupId>org.example</groupId>
<!--项目id-->
<artifactId>study_01</artifactId>
<!--版本号-->
<version>1.0-SNAPSHOT</version>
<!--打包方式-->
<packaging>pom</packaging>
<!--项目所有依赖-->
<dependencies>
<!--具体的依赖项-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--添加插件,插件可以在idea右侧下使用,比如tomcat:run-->
<build>
<plugins>
<!--具体插件的内容和相关配置-->
<plugin>
<!--指定了tomcat容器插件-->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<!--相关的配置项-->
<configuration>
<port>80</port>
<url>/</url>
</configuration>
</plugin>
</plugins>
</build>
</project>
生命周期与插件
该内容比较复杂,算是maven比较底层的原理了,mvn
将生命周期分为三部分
- clean:清理
- default:构建
- site:构建项目站点
其中default
是最为核心也是最为复杂的内容,生命周期是一个抽象的概念,所有构建项目的步骤都是由插件构成的,比如常用的:clean、complia、test、package、install
都属于插件中的一部分,其中还有很多的阶段。
依赖管理
-
依赖配置
项目中需要使用的依赖,就可以通过在
pom.xml
中来进行配置,比如<dependencies> <!--具体的依赖项--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <dependency> ... </dependency> ... </dependencies>
-
依赖传递
-
概念从名称就能知道,不同项目的依赖,比如上图中项目A引用了项目B,项目B引用的项目C就传递给了项目A,这也就分为两类
-
直接传递:对于引用项目B的项目A来说,这就是直接传递
-
间接传递:对于通过中间项目B传递了一次的项目C和项目A的关系来讲,这就是间接传递
-
-
当发生依赖的版本发生冲突,并且不使用下面的可选依赖和排除依赖时,整体来讲会根据就近原则选择依赖
-
-
可选依赖(不透明)
将项目B的某些和项目A发送冲突的依赖设置为true(即项目A看不到项目B的这样依赖项)
<!--项目B的依赖log4j设置optional为true,此时项目A将看不到项目B的该依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> <optional>true</optional> </dependency>
-
排除依赖(不需要)
与上面的可选依赖的主动将自身的依赖设置为不可见不同,排除依赖是指引用的这一方项目A排除掉项目B的某些依赖
<dependency> <groupId>org.example</groupId> <artifactId>study_webapp</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
依赖范围(scope)
maven的依赖范围包括: compile(默认),provide,runtime,test,system。
- compile:表示编译范围,指A在编译时依赖B,该范围为默认依赖范围。编译范围的依赖会用在编译,测试,运行,由于运行时需要,所以编译范围的依赖会被打包。
- provide:provide依赖只有当jdk或者一个容器已提供该依赖之后才使用。provide依赖在编译和测试时需要,在运行时不需要。例如:servlet api被Tomcat容器提供了。
- runtime:runtime依赖在运行和测试系统时需要,但在编译时不需要。例如:jdbc的驱动包。由于运行时需要,所以runtime范围的依赖会被打包。
- test:test范围依赖在编译和运行时都不需要,只在测试编译和测试运行时需要。例如:Junit。由于运行时不需要,所以test范围依赖不会被打包。
- system:system范围依赖与provide类似,但是必须显示的提供一个对于本地系统中jar文件的路径。一般不推荐使用。
思考及了解:
项目A引用项目B中的依赖,而该依赖设置了范围为test
,那么项目A还能读取到该依赖吗?
仅作了解即可
后续为maven的进阶学习
分模块开发
即是将一个单体的服务拆分成若干个更小的模块,各个模块都是maven
项目,说简单点就将一个大的maven
项目拆分成更小的多个maven
项目,这样做的意义契合现在的微服务思想,更小的模块各司其职,但是对于各模块的治理难度上升了,但是maven
有很多的解决方法
聚合
创建一个项目模块用作统一构建各个模块,通过指定packaging
为pom
指定项目为统一构建的项目,并且该不需要src目录,因为它只用做构建管理。创建其他子模块,可以与该项目同级,也可以放置在该项目里面
// 放置在同级
project
->project_manager
->pom.xml
->project_module01
->src
->pom.xml
->project_module02
->src
->pom.xml
// 放置在project_manager的目录下
project
->project_manager
->pom.xml
->project_module01
->src
->pom.xml
->project_module02
->src
->pom.xml
构建管理的pom.xml
说明
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>study_partent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--pom指定该项目统一构建管理-->
<packaging>pom</packaging>
<modules>
<module>../study_01</module>
<module>../study_webapp</module>
</modules>
</project>
继承
在上面的聚合的基础上,进一步对各模块进行管理,在这里可以将其划分为父工程和子工程,父工程的作用是统一构建管理,以及规定子工程各依赖的版本号
-
指定父工程
子工程指定父工程,如下通过在子工程的
pom.xml
中添加parent
标签,即可指定父工程,由于指定了父工程,所以子工程的groupId
和version
也应该和父工程保持一致,即删除了子工程的groupId
和version
<parent> <groupId>org.example</groupId> <artifactId>study_partent</artifactId> <version>1.0-SNAPSHOT</version> <!--指定父工程的pom.xml的相对位置--> <relativePath>../study_partent/pom.xml</relativePath> </parent> <!--maven pom的模型版本,不需要修改--> <modelVersion>4.0.0</modelVersion> <!--项目id--> <artifactId>study_01</artifactId> <!--打包方式--> <packaging>jar</packaging>
-
规定版本号
父工程通过
<dependencyManagement>
和<pluginManagement>
分别管理子工程依赖和插件的相应版本。通过自定义属性和**占位符$**管理父工程下的版本依赖,子工程需要引用依赖时,如果父工程指定了版本号,那么子工程不需要再指定版本号(仅仅只是版本号)。ps:父工程尽可能多的指定相关的版本号规范,但不意味着子工程不需要显示添加依赖了,子工程需要使用时,也需要添加依赖,只是不再添加版本。
<properties> <log4j.version>1.2.16</log4j.version> <tomcat7.plugin.version>2.2</tomcat7.plugin.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j.version}</version> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>${tomcat7.plugin.version}</version> <configuration> <port>80</port> <url>/</url> </configuration> </plugin> </plugins> </pluginManagement> </build>
属性
maven的pom.xml有五种属性,使用的比较多的,也比较重要的是自定义属性,为统一管理版本号提供了方法
<properties>
<log4j.version>1.2.16</log4j.version>
<tomcat7.plugin.version>2.2</tomcat7.plugin.version>
</properties>
配置文件绑定pom.xml
的自定义属性
产生的前提:
项目中有很多的配置文件,比如application.xml
或者application.properties
,这些配置文件通常都存放在resources
文件夹下,当多个子模块都有配置文件时,那么该怎么去方便的管理这些配置文件里的内容呢?比如想要统一管理所有子模块的数据库连接地址,不可能手动到每个模块的配置文件中去修改。所以maven支持通过在pom.xml
文件中设置自定义属性和使用<resource>
指明资源路径的方式,来动态的管理配置文件中的变量。而配置文件使用两种方式来设置占位符
- ${自定义属性名称}
- @自定义属性名称@
...
<properties>
<jdbc.username>hhh</jdbc.username>
</properties>
...
<build>
<!--指定main下的相关资源-->
<resources>
<resource>
<!--指定配置文件的路径-->
<directory>${project.basedir}/src/main/resources</directory>
<!--是否开启映射自定义属性到资源文件-->
<filtering>true</filtering>
</resource>
</resources>
<!--指定test下的相关资源-->
<testResources>
<testResource>
<!--指定配置文件的路径-->
<directory>${project.basedir}/src/test/resources</directory>
<!--是否开启映射自定义属性到资源文件-->
<filtering>true</filtering>
</testResource>
</testResources>
</build>
配置文件里的内容:
# 使用$或者@@都可以获取到pom.xml的自定义属性内容
jdbc.username=${jdbc.username}
jdbc.test=@jdbc.username@
jdbc.password=123456
其中使用到了<resource>
标签,这个标签放置在<build>
下,是很重要的标签,能添加一些资源或者排除一些资源。等待后续更加深入的学习。
多环境配置
在实际的项目开发中肯定包含了很多不同的环境,比如开发环境、测试环境、生产环境。所以配置也应该有多套不同的配置。maven提供了不同的配置<profiles>
,其中自定义标签可以在构建项目时进行勾选,maven的不同选择,会让配置文件读取的自定义属性不一样。再搭配springboot
里的profile
能配置多个配置文件,就能控制更多的配置文件了
<profiles>
<profile>
<id>dev</id><!-- 开发环境 -->
<properties>
<profileActive>dev</profileActive>
</properties>
</profile>
<profile>
<id>test</id><!-- 测试环境 -->
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
<profile>
<id>pro</id><!-- 生产环境 -->
<properties>
<profileActive>pro</profileActive>
</properties>
</profile>
</profiles>
上传到远程仓库(私服)
公司内部开发会搭建相应的私服,用以存放内部开发的一些包,同时也方便其他开发人员的下载。私服上的仓库可以分为以下几类
- 代理仓库:私服代理从其他的公共仓库中获取志愿,例如代理从中央仓库中获取资源
- 宿主仓库:用户在私服上创建的仓库,用户将一些内部使用的资源上传到这里面,供公共使用
- 仓库组:将多个仓库归类到一个组,这样在获取资源时,可以指定获取这个组内的所有 资源,是一个方便管理的抽象概念
相关配置的方法可以参考博客,配置好后使用depoly
将生成的包发布到私服中
遗留问题或待深入理解
- 将所有子模块的配置文件抽取成一个公共的
config
组件,各个application.yml
使用占位符读取公共配置组件里的内容。目前是可行,但是创建的maven子模块读取到config
公共组件的配置还有点问题,感觉像是与springboot的application.yml和application-dev.yml
关系有关。待后续研究吧。 mvn
的生命周期和插件