【maven】一篇文章带你领略企业级maven!(万字)

maven依赖

0、结构

<dependency>
	<groupId></groupId>
	<artifactId></artifactId>
	<version></version>
    <!--默认是jar  取值有:jar war pom等-->
	<type></type>
	<scope></scope>
    <!--此配置会让依赖传递失效,不会向上传递。比较少用!-->
	<optional></optional>
</dependency>

1、maven的dependency中依赖范围取值<scope></scope>

  • compile:

    默认。对编译、测试和运行的classpath都有效。

  • test:

    仅对于运行测试代码的classpath有效,编译或者运行主代码的时候无效。

  • provided:

    编译和测试的时候有效,但是在运行的时候无效。比如:tomcat提供的servlet-api。

  • runtime:

    测试和运行classpath有效,但是编译代码时无效。比如mysql驱动,写代码时是基于javax.sql包下的标准接口进行编码在编译期间仅用到javax.sql接口即可,在测试、运行则需要用这个包。

  • import

    maven多模块项目结构中,可以使用parent 定义父项目,实现从父项目中继承依赖。但maven只能单继承,即一个项目只能使用一个parent标签定义父项目。
    maven2.9之后的版本引入了一个新的功能,可以实现依赖上的多重继承。这个功能可以将依赖配置复杂的pom文件拆分成多个独立的pom文件。这样处理可以使得maven的pom配置更加简洁,同时可以复用这些pom依赖。

    比如,我们在开发spring boot 项目的时候,pom中会有如下配置:

    <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>1.3.3.RELEASE</version>
    </parent>
    

    如果该项目除引用spring-boot-starter-parent为父工程外,还有一个父工程需要使用parent来表示父子关系的话,就会出现问题。

    由于maven类似java是单继承,不能有两个parent,现在<parent></parent>标签已经用来引用父模块,现在又用来引用springboot,就会产生冲突。

    那解决办法就是:使用dependencyManagement引入dependency,并且把scope属性改为import。如下:

    <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-dependencies</artifactId>
             <version>2.1.6.RELEASE</version>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
    </dependencyManagement>
    
    <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
    </dependencies>
    

    注意:scope的import 属性只能在<dependencyManagement> 中使用,表示从其它的pom文件中导入dependency配置。

2、maven的传递性依赖

maven中传递性依赖机制对依赖范围的影响如下表:

compiletestprovidedruntime
compilecompileruntime
testtesttest
providedprovidedprovidedprovided
runtimeruntimeruntime

3、maven的依赖调节

  • 就近原则:

    A->B->C->X(1.0),A->D->X(2.0) 会选择2.0

  • 第一声明原则

    A->B->X(1.0)、A->D->X(2.0)谁先声明选择谁

4、maven的可选依赖

<optional>true</optional>

此配置会让依赖传递失效,不会向上传递。注意:很少使用

5、maven的依赖冲突解决

查询依赖冲突位置

1、mvn dependency:tree

此命令可以看整个项目的依赖路径树

image-20201203165017197

2、在Idea中可以直接使用maven的show Dependcies功能直接查看。

image-20201203170343806

找到冲突的jar后进行排除依赖<exclusion></exclusion>

<dependency>
<groupId>A</groupId>
<artifactId>A</artifactId>
<version>1.0</version>
<exclusions>
		<exclusion>
			<groupId>C</groupId>
			<artifactId>C</artifactId>
		</exclusion>
</exclusions>
</dependency>

maven仓库

1、maven的多仓库架构图

maven多层仓库架构

2、maven本地仓库

本地仓库默认路径

windows默认路径是~.m2\repository

linux默认路径是/home/root/.m2/repository

修改本地仓库默认路径

~/.m2/settings.xml配置文件里:

某路径

3、maven中央仓库

maven的默认配置:

image-20201203175158341

在maven安装目录的lib中存在maven-model-builder的jar。解压后里面有一个自带的超级pom.xml文件,里面配置了一个默认的中央仓库。

<repositories>
	<repository>
		<id>central</id>
		<name>Maven Repository Switchboard</name>
		<url>http://repo1.maven.org/maven2</url>
		<layout>default</layout>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>

4、maven私服

  1. nexus安装、启动、登录和默认配置

    nexus下载官网:

    https://sonatype-download.global.ssl.fastly.net/repository/downloads-prod-group/3/nexus-3.28.1-01-win64.zip

    nexus目录:

    nexus-3.28.1-01:这里包含nexus运行需要的文件

    sonatype-work:包含nexus的配置文件、日志文件、仓库文件

    nexus启动:

    windows:进入到nexus的bin目录下,里面有一个nexus.exe这个文件,执行命令nexus.exe/run 启动nexus服务,这块要等个三五分钟,启动很慢,直到出现下图才启动成功。

    image-20201204055100950

    nexus配置:

    端口号等配置路径

    nexus\nexus-3.28.1-01\etc\nexus-default.properties

    虚拟机参数配置路径:

    nexus\nexus-3.28.1-01\bin\nexus.vmoptions

    nexus登录:

    默认端口号:8081

    默认访问地址:http://localhost:8081

    系统登录用户名:admin

    密码如下图:

    image-20201204055328221

    登录后配置:

    是否允许匿名访问私服下载jar

    image-20201204055414776

  2. nexus仓库使用图

    nexus仓库架构

  3. nexus仓库

    image-20201204060900912

    仓库类型

    hosted

    宿主仓库,是用来把公司内部的发布包部署到此仓库里,公司内的其他人在此宿主仓库里下载依赖去使用。

    proxy

    代理仓库,代理了公司外部的各种仓库的,比如说java.net,codehaus,jboss仓库,最重要的就是代理了公司外部的中央仓库,但是这里其实可以修改为nexus连接的应该是国内的阿里云镜像仓库,阿里云去连接中央仓库。

    group

    仓库组,将各种宿主仓库、代理仓库全部组成一个虚拟的仓库组,然后项目只要配置依赖于一个仓库组,就可以自动连接仓库组对应的各种仓库。

    仓库格式

    maven1或者maven2,现在统一都是maven2

    maven2类型仓库讲解

    maven-central

    maven中央仓库的代理仓库

    maven-releases

    宿主仓库,用于部署公司内部的release版本的发布包(类似于1.0.0,release的意思就是你的工程已经经过了完善的测试,单元测试,集成测试,QA测试,上生产环境使用了)

    maven-snapshots

    宿主仓库,用于部署公司内部的snapshot版本的发布包到这个仓库里(如果你的某个工程还在开发过程中,测试还没结束,此时公司里其他同事也在开发一些工程,需要依赖你的包进行开发和测试,联调,此时你的工程的版本就是类似1.0.0-SNAPSHOT这样的版本)。

    3rd party

    宿主仓库,默认没有要自己手动创建。主要用来部署没法从公共仓库获取的第三方依赖包。比如说,你的公司依赖于第三方支付厂商的一个依赖包,那个依赖包不是开源的,是商业的包。此时,我们需要手动上传到此仓库中。目前fastdfs-java-client的包也是这个状态。

    maven-public

    仓库组。注意:仓库组中配置的顺序即为拉取jar的顺序。

    nexus仓库配置

    maven-central代理仓库

    从直接代理maven中央仓库,修改为代理阿里云仓库

    http://maven.aliyun.com/nexus/content/groups/public

    image-20201204062042080

    3rd party仓库

    手动创建此仓库

    把此仓库加入到maven-public仓库组中

    image-20201204062423992

    nexus用户

    用户类型

    1. admin 管理员账号
    2. deployment 可以搜索和部署构建,就是普通的开发账号。目前没有需要手动创建
    3. anonymous:如果没有给认证信息,就是这个匿名账号,可以下载依赖,查看依赖

    用户、角色创建

    创建角色

    image-20201204065009288

    创建用户

    image-20201204065050904

  4. maven私服文件配置

    maven的settings.xml**(一般要存放于~.m2\setting.xml)**

    <!--私服的验证信息-->
    <servers>
    	<server>
      <!--此处id要与项目中的pom.xml文件的配置相对应-->
    		<id>nexus-releases</id>
    		<username>dev</username>
    		<password>dev123</password>
    	</server>
    	<server>
      <!--此处id要与项目中的pom.xml文件的配置相对应-->
    		<id>nexus-snapshots</id>
    		<username>dev</username>
    		<password>dev123</password>
    	</server>
       <!--手动上传第三方jar时,使用命令会用到-->
      <server>
         <id>nexus-3rd-party</id>
         <username>dev</username>
         <password>dev123</password>
      </server>
    </servers>
    <!--强制从公司内的私服来下载,不允许走外网。-->
    <!--maven对全部仓库的访问全部拦截到私服的public仓库中去,如果私服关闭,那么就不能访问中央工厂了-->  
    <mirrors>  
      <mirror>  
          <id>nexus</id>  
          <mirrorOf>*</mirrorOf>  
          <name>Local Repository</name>
          <!-- 如果是自己玩,把下面的路径配置成阿里云就可以啦!-->
          <!--私服的链接点击nexus面板上的copy即可复制。-->
          <url>http://127.0.0.1:8081/nexus/content/groups/public</url>  
      </mirror>  
    </mirrors> 
    <!--配置仓库的一些信息,其主要作用是用来覆写超级pom.xml中的central中央仓库的一些配置信息-->  
    <profiles>
    	<profile>
    		<id>nexusProfile</id>
            <repositories>
                <repository>
                      <!--此id不能变-->
                        <id>central</id>
                        <name>central</name>
                      <!-- 该 url 没有意义,可以随便写,但必须有。 -->  
                        <url>http://central</url>
                        <releases><enabled>true</enabled></releases>
                        <snapshots><enabled>true</enabled></snapshots>
                </repository>
            </repositories>
         	<!--插件的仓库配置-->    
            <pluginRepositories>
                <pluginRepository>
                      	<!--此id不能变-->
                        <id>central</id>
                        <name>local private nexus</name>
                      	<!--私服的链接点击nexus面板上的copy即可复制。-->
                        <url>http://localhost:8081/nexus/content/groups/public</url>
                        <releases><enabled>true</enabled></releases>
                        <snapshots><enabled>true</enabled></snapshots>
                </pluginRepository>
            </pluginRepositories>
    	</profile>
    </profiles>
    <!--激活上面配置的仓库信息--> 
    <activeProfiles>
    	<activeProfile>nexusProfile</activeProfile>
    </activeProfiles>
    

    项目中的pom.xml配置:

    注意:如果想发布到snapshot仓库中,则需要在版本号后加上 -SNAPSHOT (注意这里必须是大写)

    <!-- 项目部署到私服配置 -->  
    <distributionManagement> <!-- 远程部署管理信息 -->  
     <repository> <!--部署项目产生的构件到远程仓库需要的信息 -->  
         <!--此处id要与maven中的setting.xml文件的配置相对应-->
         <id>nexus-releases</id>  
         <name>Nexus Release Repository</name>  
     	 <url>http://localhost:8081/nexus/content/repositories/releases/</url>  
     </repository>  
    
     <snapshotRepository> <!-- 如果没有配置该元素,默认部署到repository元素配置的仓库 -->  
         <!--此处id要与maven中的setting.xml文件的配置相对应-->
         <id>nexus-snapshots</id>  
         <name>Nexus Snapshot Repository</name>  
         <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>  
     </snapshotRepository>  
    
    </distributionManagement> 
    
  5. maven的jar部署

    使用maven命令:mvn clean deploy

    mvn clean package:清理、编译、测试、打包

    mvn clean install:清理、编译、测试、打包、安装到本地仓库

    mvn clean deploy:清理、编译、测试、打包、安装到本地仓库、部署到远程私服仓库

    手动上传jar

    mvn deploy:deploy-file -DgroupId=com.csource -DartifactId=fastdfs-client-java -Dversion=1.24 -Dpackaging=jar -Dfile=F:\fastdfs_client_v1.24.jar -Durl=http://localhost:8081/repository/3rd-party/ -DrepositoryId=nexus-3rd-party

maven生命周期

1、解释:

  • maven生命周期,就是去解释mvn各种命令背后的原理。
  • 清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成。
  • Maven的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成。

2、maven的三大生命周期

maven有三套相互独立的生命周期,分别是cleandefaultsite

每个生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段,每个phase又是由各种插件的goal来完成的,一个插件的goal可以认为是一个功能。如下图:

04_maven生命周期原理

1、clean生命周期:清理项目,包含三个phase:

1)pre-clean:执行清理前需要完成的工作

2)clean:清理上一次构建生成的文件

3)post-clean:执行清理后需要完成的工作

2、default生命周期:构建项目,重要的phase如下:

1)validate:校验这个项目的一些配置信息是否正确

2)initialize:初始化构建状态,比如设置一些属性,或者创建一些目录

3)generate-sources:自动生成一些源代码,然后包含在项目代码中一起编译

4)process-sources:处理源代码,比如做一些占位符的替换

5)generate-resources:生成资源文件,才是干的时我说的那些事情,主要是去处理各种xml、properties那种配置文件,去做一些配置文件里面占位符的替换

6)process-resources:将资源文件拷贝到目标目录中,方便后面打包

7)compile:编译项目的源代码

8)process-classes:处理编译后的代码文件,比如对java class进行字节码增强

9)generate-test-sources:自动化生成测试代码

10)process-test-sources:处理测试代码,比如过滤一些占位符

11)generate-test-resources:生成测试用的资源文件

12)process-test-resources:拷贝测试用的资源文件到目标目录中

13)test-compile:编译测试代码

14)process-test-classes:对编译后的测试代码进行处理,比如进行字节码增强

15)test:使用单元测试框架运行测试

16)prepare-package:在打包之前进行准备工作,比如处理package的版本号

17)package:将代码进行打包,比如jar包

18)pre-integration-test:在集成测试之前进行准备工作,比如建立好需要的环境

19)integration-test:将package部署到一个环境中以运行集成测试

20)post-integration-test:在集成测试之后执行一些操作,比如清理测试环境

21)verify:对package进行一些检查来确保质量过关

22)install:将package安装到本地仓库中,这样开发人员自己在本地就可以使用了

23)deploy:将package上传到远程仓库中,这样公司内其他开发人员也可以使用了

3、site生命周期:建立和发布项目站点,phase如下:

1)pre-site:生成项目站点之前需要完成的工作

2)site:生成项目站点文档

3)post-site:生成项目站点之后需要完成的工作

4)site-deploy:将项目站点发布到服务器

注意:每个生命周期的phase都是顺序执行的,而且是后面的依赖于前面的phase,比如执行 mvn complie(第七步),就需要先完成前六步再执行complie的phase。

4、默认的phase绑定了哪些plugin goal?
Plugingoal
process-resourcesresources:resources
compilecompiler:compile
process-test-resourcesprocess-test-resources
test-compilecompiler:testCompile
testtest
packagejar:jar或者war:war
installinstall:install
deploydeploy:deploy

类似于compiler:testCompile这种格式,就是compiler这个plugin的testCompile goal(testCompile功能,负责编译测试代码)

5、maven的命令行

比如:mvn clean package

clean是指的clean生命周期中的clean phase

package是指的default生命周期中的package phase

此时就会执行clean生命周期中,在clean phase之前的所有phase。包括了:clean phase,pre clean,clean(其中pre clean phase默认是没有绑定任何一个plugin goal的,所以默认什么也不会干。

同时也会执行default生命周期中,在package phase之前的所有phase和package phase。

比如:mvn dependency:tree 或者 mvn deploy:deploy-file

这种命令就是不执行任何一个生命周期的任何一个phase直接执行指定的插件的一个goal!

mvn dependency:tree,就是直接执行dependency这个插件的tree这个goal,这个意思就是会自动分析pom.xml里面的依赖声明,递归解析所有的依赖,然后打印出一颗依赖树。

mvn deploy:depoy-file,就是直接执行deploy这个插件的deploy-file这个goal,这个意思就是说将指定目录的jar包,以指定的坐标,部署到指标的maven私服仓库里去,同时使用指定仓库id对应的server的账号和密码。

maven插件(plugin)

我们为什么要用插件:

**1、比如:**maven进行打包时默认不会把其他引用的jar给打包进去,此时就需要用到下面的maven插件:

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>

**2、比如:**在单元测试执行完之后,计算出单元测试对我们所有代码的一个覆盖率。此时也需要使用一个第三方的cobertura插件。

<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
**3、比如:**在ide里面随时很轻易的就启动一个web容器,然后输入链接即可进行冒烟测试,此时也需要使用一个第三方的jetty插件。(不常用)

插件plugin是什么:

其实就是一个jar包,存在于仓库里面的,拉取下来后可以在本地仓库找到。

maven如何提供支持的?

maven中少数一些phase绑定了一些maven内置的插件的goal,相当于有大量的phase其实是空置的。maven这样做的目的就是方便别人开发插件时要在指定时间执行某些方法而设置的回调机制。

我们可以在pom.xml文件里面来配置这个插件绑定到哪个phase上面去。在maven的命令执行的时候,如果你绑定了某个第三方的插件到phase,此时插件就会执行,然后实现插件的功能。

maven的plugin使用

resources介绍:

resources配置的是当执行资源打包的时候,指定哪些资源进行打包。

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*</include>
        </includes>
        <filtering>true</filtering>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
        </includes>
        <filtering>true</filtering>
    </resource>
</resources>

注意:filtering是为<directory>中定义的目录开启资源过滤功能,让maven resources插件在处理资源的时候自动去解析里面的占位符,然后找到对应profile里的实际值来进行替换。使用方法在下面maven的profile中会讲到。

将插件的goal绑定到phase上

比如:有一个插件source可以打包含源码的jar包,接下来就是将source插件的jar-no-fork goal绑定到verify phase,在完成集成测试之后,就生成源码的jar包。[有不少开源的项目,不仅仅会给你提供下载一个可以立即使用的jar包,还会给你提供一个用src结尾的一个jar包,那个jar包里放的就是那个开源项目的源码。]

<build>
	<plugins>
		<plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-source-plugin</artifactId>
			<version>2.1.1</version>
			<executions>
				<execution>
					<id>attach-sources</id>
					<phase>verify</phase>
					<goals>
						<goal>jar-no-fork</goal>
					</goals>
				</execution>
			</executions>
            <configuration>
            	<outputDirectory>${project.build.outputDirectory}</outputDirectory>
            </configuration>
		</plugin>
	</plugins>
</build>

其中:

  • <execution> 是指这个插件在什么时候进行执行,可以配置多个execution。
  • **<id>**是他的名字
  • <phase><goals> 向那个phase里面绑定了哪些goal,这里是向verify phase绑定jar-no-fork goal。结合maven的生命周期进行配置。[verify是对package进行一些检查来确保质量过关],不配置绑定的phase也可以,因为大多数插件都默认内置了要绑定的phase,比如这个插件就内置绑定在package phase。
  • <configuration> 插件配置下面进行介绍

**注意:上面的插件可以使用maven的生命周期进行使用:运行mvn verify就可以看到生成了一个包含源码的jar包。**如果不配置phase那么执行的命令是mvn package。

配置插件

如果在命令行执行插件,可以用-Dkey=value来进行插件的设置

比如mvn install -Dmaven.test.skip=true,就是surefire插件在测试的时候提供的参数,设置为true就会跳过测试

此外也可以在pom.xml中用来配置

<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>2.1</version>
			<configuration>
				<source>1.5</source>
				<target>1.5</target>
			</configuration>
		</plugin>
	</plugins>
</build>
插件仓库(maven仓库模块有配置)

先从本地仓库找插件,没有则从远程仓库找插件

插件的远程仓库也需要配置,maven默认配置了远程的插件仓库

<!--插件的仓库配置-->    
<pluginRepositories>
    <pluginRepository>
        <!--此id不能变-->
        <id>central</id>
        <name>local private nexus</name>
        <!--私服的链接点击nexus面板上的copy即可复制。 默认http://repo1.maven.org/maven2-->
        <url>http://localhost:8081/nexus/content/groups/public</url>
        <releases><enabled>true</enabled></releases>
        <snapshots><enabled>true</enabled></snapshots>
    </pluginRepository>
</pluginRepositories>

maven的属性(properties)标签的使用(五种风格)

maven的properties官方说明

1、env.X:使用“env”来定义变量。将返回shell的环境变量。例如,**${env.PATH}**包含PATH环境变量。

注意:虽然环境变量本身在Windows上不区分大小写,但查找属性区分大小写。换句话说,虽然Windows shell为**%PATH%%Path%返回相同的值,但Maven区分 e n v . P A T H ∗ ∗ 和 ∗ ∗ {env.PATH}**和** env.PATH{env.Path}**。对于Maven 2.1.0,为了可靠性,环境变量的名称被归一化为所有大写。

2、project.x:POM中的点(.)记号路径将包含相应元素的值。

例如:

<build>
 <resources>
     <resource>
         <filtering>true</filtering>
         <directory>${project.basedir}/src/main/resources</directory>
         <includes>
             <include>*.properties</include>
         </includes>
     </resource>
 </resources>
</build>

还有一些内置的变量,如下:

** p r o j e c t . b a s e d i r ∗ ∗ : 这 引 用 了 ∗ ∗ m o d u l e / p r o j e c t ∗ ∗ 的 根 文 件 夹 ( 当 前 p o m . x m l 文 件 所 在 的 位 置 ) , 还 可 以 简 化 的 写 法 : {project.basedir}**:这引用了**module/project**的根文件夹(当前pom.xml文件所在的位置),还可以简化的写法: project.basedirmodule/projectpom.xml{basedir}

以上更多用法参考:http://maven.apache.org/ref/3.5.0/maven-model-builder/#Model_Interpolation

${project.build.directory}:这表示默认的target文件夹。

${project.build.outputDirectory}:默认情况下表示target/classes文件夹。

${project.build.testOutputDirectory}:这表示默认的target/test-classes文件夹。

${project.build.sourceDirectory}:这表示默认情况下src/main/java文件夹。

${project.build.testSourceDirectory}:这表示默认情况下src/test/java文件夹。

p r o j e c t . b u i l d . f i n a l N a m e ∗ ∗ : 默 认 情 况 下 定 义 为 ∗ ∗ {project.build.finalName}**:默认情况下定义为** project.build.finalName{project.artifactId}-${project.version}

${project.version}:这可以在必须编写文字版本的位置使用,否则,特别是如果您在多模块构建模块间依赖关系。

以上更多用法参考:http://maven.apache.org/pom.html#The_Super_POM

s e t t i n g s . l o c a l R e p o s i t o r y ∗ ∗ : 它 引 用 了 本 地 存 储 库 的 位 置 。 这 是 默 认 的 ∗ ∗ {settings.localRepository}**:它引用了本地存储库的位置。这是默认的** settings.localRepository{home}/.m2/repository

以上更多用法参考:http://maven.apache.org/pom.html#Properties

以上参考:https://cwiki.apache.org/confluence/display/MAVEN/Maven+Properties+Guide

3、settings.xsettings.xml中的点(.)标注路径将包含相应的元素的值。

例如:**<settings><offline>false</offline></ settings>可通过${settings.offline}**访问。

4、Java系统属性:可通过**java.lang.System.getProperties()**访问的所有属性都可用作POM属性。

例如:${java.home}

5、x:在POM中的<properties/>元素中设置。

可以使用在pom文件的任意地方或者properties文件中使用。

例如:用来统一项目中jar的版本号,最常用。

<properties>
	<target.version>2.5.6</target.version>
</properties>
<dependencies>
 <dependency>
     <groupId>your groupId</groupId>
     <artifactId>your artifactId</artifactId>
     <version>${target.version}</version>
 </dependency>
</dependencies>

例如:不常用

pom.xml文件中

<properties>
	<jdbc.driverClassName>com.mysql.jdbc.Driver</jdbc.driverClassName>
 <jdbc.url></jdbc.url>
 <jdbc.username>root</jdbc.username>
 <jdbc.password>123456</jdbc.password>
</properties>

项目文件src/main/resources/jdbc.properties的文件,写入如下所示:

jdbc.driverClassName=${jdbc.driverClassName}
jdbc.url=${jdbc.url}
jdbc.username=${jdbc.username}
jdbc.password=${jdbc.password}

maven模块module

为什么要用maven的module

如果我们有50个子项目,每个项目都要某个基础模块,那么此时需要手工运行50次构建的命令,让50个模块都依次去构建和测试。

这样是极其麻烦的,所以maven提供了一个解决方案:聚合功能。

聚合功能就是可以将各个模块聚合成一个大的模块给它一个父工程,父模块,那个父模块里面配置聚合了哪些子模块。

只要对父模块运行一次构建命令,此时maven会自动对这个父模块下面的所有子模块都运行相应的构建命令,这样就保证一键自动化构建所有的模块,不要一个一个依次去构建。

注意:父工程也需要部署到私服里面,父工程的pom也需要私服配置。否则其他人员引用父工程会报错。

moudle使用:

1、搭建项目工程:

ausnatures-java为父工程

ausnatures-commom为通用模块

ausnatures-generator为逆向代码生成模块

ausnatures-logging为日志模块

ausnatures-system为系统模块

ausnatures-tools为工具模块

image-20201206071628249
2、配置pom文件

父工程:打包方式必须为pom

<groupId>com.ausnatures</groupId>
<artifactId>ausnatures</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
    <module>ausnatures-common</module>
    <module>ausnatures-logging</module>
    <module>ausnatures-system</module>
    <module>ausnatures-tools</module>
    <module>ausnatures-generator</module>
</modules>

子工程:

<parent>
    <artifactId>ausnatures</artifactId>
    <groupId>com.ausnatures</groupId>
    <version>1.0.0-SNAPSHOT</version>
    <!-- 可以不写,默认值为: ../pom.xml -->
    <relativePath/> 
</parent>

注意:<relativePath>表示父模块POM的相对路径,在构建的时候,Maven会先根据relativePath检查父POM,如果找不到,再从本地仓库查找。默认值为 …/pom.xml

3、被继承的元素

groupId:项目组ID,项目坐标的核心元素
version: 项目版本, 项目坐标的核心元素
description: 项目的描述信息
organization: 项目的组织信息
inceptionYear: 项目的创始年份
url: 项目的URL地址
developers: 项目开发者信息
contributors: 项目的贡献者信息
distributionManagement: 项目的部署配置
issueManagement: 项目的缺陷跟踪系统信息
ciManagement: 项目的持续集成系统信息
scm: 项目的版本控制系统信息
mailingLists: 项目的邮件列表信息
properties: 自定义的maven属性
dependencies: 项目的依赖配置
dependencyManagement: 项目的依赖管理配置
repositories: 项目的仓库配置
build: 包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
reporting: 包括项目的报告输出目录配置、报告插件配置等

maven的依赖管理(dependencyManagement)与插件管理(pluginManagement)

为什么要用依赖管理和插件管理:

我们知道dependencies是可以被继承的,这个时候我们就想到让我们共用的依赖转移到parent中。可是问题也随之而来,如果有一天我创建了一个新的模块,但是这个模块不需要这些parent的依赖,这时候如何处理?

maven的依赖管理就是来解决这个问题的。

使用依赖管理和插件管理

在父工程中,使用<depdendencyManagement>和<pluginManagement>两个元素,来声明要被子工程继承的依赖和插件。

子模块继承这些配置的时候,仍然要声明groupId和artifactId,表示当前配置是继承于父POM的,从而直接使用父POM的版本对应的资源。只要声明groupId和artifactId即可,不需要声明version版本号,因为version全部放在父工程中进行了统一声明。

父工程:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>your groupId</groupId>
            <artifactId>your artifactId</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</dependencyManagement>

子工程:

<dependencies>
    <dependency>
        <groupId>your groupId</groupId>
        <artifactId>your artifactId</artifactId>
    </dependency>
</dependencies>

注意:如果子工程dependencies中的dependency声明了version,那么无论父工程dependencyManagement中有无对该jar的version声明,都以子工程dependency里的version为准

子工程中要继承两个父工程怎么办?

比如,我们在开发spring boot 项目的时候,pom中会有如下配置:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.3.RELEASE</version>
</parent>

但是,如果该项目是个maven子模块的话,就会出现问题。由于maven类似java是单继承,不能有两个parent,现在<parent></parent>标签已经用来引用父模块,现在又用来引用springboot,就会产生冲突。

那解决办法就是:使用dependencyManagement引入dependency,并且把scope属性改为import。如下:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
 
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

注意:scope的import 属性只能在<dependencyManagement> 中使用,表示从其它的pom文件中导入dependency配置。

maven的profile

介绍

在开发过程中,我们的项目会存在不同的运行环境,比如开发环境、测试环境、生产环境,而我们的项目在不同的环境中,有的配置可能会不一样,比如数据源配置、日志文件配置、以及一些软件运行过程中的基本配置,那每次我们将软件部署到不同的环境时,都需要修改相应的配置文件,这样来回修改,很容易出错,而且浪费劳动力。
虽然SpringBoot为我们提供了一种解决方案,但是maven也提供了一种更加灵活的解决方案,就是profile功能。

环境介绍

一般我们的项目都有多个环境,常见的是这么几个环境:

  1. dev:

    即本地的开发和测试环境,这个就是指的是我们自己本地的笔记本电脑,在上面可以进行开发、单元测试、冒烟测试。本地环境需要有一些基础性的依赖设施,比如说数据库、MQ、redis,这些东西都是部署在公司的一套公共的一个dev环境。

  2. beta

    一般称作内部测试环境,也就是不对外。集成测试/联调测试的环境,程序员开发好了之后,需要将自己的代码部署到一个集成测试环境。有的公司也叫做联调测试环境。

    通俗的讲,就是一个项目都是多个研发人员,每个人写好自己的部分之后都要发布到一个环境,大家在此环境进行测试保证整个系统、多个服务能串起来跑的通。

  3. test

    QA测试环境,会有专门的测试人员进行测试。需要将通过集成测试的代码,部署到QA测试环境,然后由QA人员进行非常充分而且完善的测试、验证功能、性能等各个方面都没有问题。

  4. staging

    预发布环境,通常这个环境会跟生产环境保持基本一致,部署到上面之后,就会使用部分真实的流量或者数据,来让系统运行。

    比如对外提供服务的网站,app之类的,可以通过流量拷贝的方式,拷贝一小部分流量过来,在staging环境让开发好的系统跑一下。后者也可以拷贝部分真实的线上数据库的数据下来,跑一下。

    这个环节QA还是会介入,再次验证一下看系统是否运行正常。同时这个环节,有一个验收的作用,项目如果有产品经理,此时会在这个环节看一下是否符合他的产品预期。

  5. prod

    生产环境,最终系统部署到线上生产环境中,完成上线。

注意:每个环境,都是完全隔离开来的,都有自己独立的数据库、mq、缓存等等各种各样的依赖。

下面我们根据这五个环境进行maven的profile演示。

基于资源过滤+profile的方式适配各个环境

我们定义一个jdbc.properties的配置文件:

local:

database.jdbc.driverClass=com.mysql.jdbc.Driver
database.jdbc.connectionURL=jdbc:mysql://localIp:3306/oa_local
database.jdbc.username=local
database.jdbc.password=local

dev:

database.jdbc.driverClass=com.mysql.jdbc.Driver
database.jdbc.connectionURL=jdbc:mysql://devIp:3306/oa_dev
database.jdbc.username=dev
database.jdbc.password=dev

首先我们要将配置对应的值从配置文件中抽取出来用占位符替代,然后实际的值放到profile里去:

database.jdbc.driverClass=${database.jdbc.driverClass}
database.jdbc.connectionURL=${database.jdbc.connectionURL}
database.jdbc.username=${database.jdbc.username}
database.jdbc.password=${database.jdbc.password}

然后在pom.xml里加入各个环境对应的profile配置:

<profiles>
    <profile>
        <!--不同环境Profile的唯一id-->
        <id>beta</id>
        <properties>
            <database.jdbc.driverClass>com.mysql.jdbc.Driver</database.jdbc.driverClass>
 <database.jdbc.connectionURL>jdbc:mysql://betaIp:3306/oa_local</database.jdbc.connectionURL>
            <database.jdbc.username>beta</database.jdbc.username>
            <database.jdbc.password>beta</database.jdbc.password>
        </properties>
    </profile>
    <profile>
        <id>dev</id>
        <properties>
            <database.jdbc.driverClass>com.mysql.jdbc.Driver</database.jdbc.driverClass>
 <database.jdbc.connectionURL>jdbc:mysql://devIp:3306/oa_dev</database.jdbc.connectionURL>
            <database.jdbc.username>dev</database.jdbc.username>
            <database.jdbc.password>dev</database.jdbc.password>
        </properties>
    </profile>
    <!--此处省略其他环境配置-->
</profiles>

此时我们要做的就是让项目在发布到不同环境的时候激活不同的profile,并且将实际值替换到占位符里。

如何将实际值替换到占位符里去呢?

为src/main/resources目录开启资源过滤功能,让maven resources插件在处理资源的时候自动去解析里面的占位符,然后找到对应profile里的实际值来进行替换。

<resources>
    <resource>
        <directory>${project.basedir}/src/main/resources</directory>
        <!--开启资源过滤功能-->
        <filtering>true</filtering>
    </resource>
</resources>
<testResources>
    <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
        <!--开启资源过滤功能-->
        <filtering>true</filtering>
    </testResource>
</testResources>

默认激活:

我们一般会设置默认激活一个profile,在profile配置里加上如下配置:

<activation>
	<activeByDefault>true</activeByDefault>
</activation>

最终配置如下代码:

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <database.jdbc.driverClass>com.mysql.jdbc.Driver</database.jdbc.driverClass>
            <database.jdbc.connectionURL>jdbc:mysql://devIp:3306/oa_local</database.jdbc.connectionURL>
            <database.jdbc.username>dev</database.jdbc.username>
            <database.jdbc.password>dev</database.jdbc.password>
        </properties>
    </profile>
    <profile>
        <id>beta</id>
        <properties>
            <database.jdbc.driverClass>com.mysql.jdbc.Driver</database.jdbc.driverClass>
            <database.jdbc.connectionURL>jdbc:mysql://betaIp:3306/oa_local</database.jdbc.connectionURL>
            <database.jdbc.username>local</database.jdbc.username>
            <database.jdbc.password>local</database.jdbc.password>
        </properties>
    </profile>
	<!--此处省略其他环境配置-->
</profiles>

使用:

mvn clean package -Pdev -P就是说激活dev profile

查看target/classes下面的资源文件,全都替换为了dev profile中的实际值。

可以用mvn help:active-profiles 查看当前激活的是哪个profile

不同地方配置profile

profile实际上是可以在不同地方进行配置。

比如:在settings.xml里,我们也通过配置profile、激活profile来配置maven私服仓库地址;在maven的超级pom里,也有一些profile激活。

大型项目中maven profile的应用场景

在大型项目里面配置文件特别多,不可能把所有的配置都放profiles里面,那怎么办呢?

不在src/main/resources放配置文件了,在profile里面定义一个单独属于自己的环境的一套配置文件对应的目录,然后在处理资源文件的时候,会把激活的profile对应的一套目录里的资源文件拷贝到src/main/resources下面去,给工程打包使用。

目录结构如下:

image-20201206192116609

pom.xml文件配置:

<profiles>
    <!-- 每个profile对应了一个环境下的一套配置 -->
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <build>
            <resources>
                <resource>
                    <directory>src/main/profiles/dev</directory>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                    </includes>
                    <filtering>true</filtering>
                </resource>
            </resources>
        </build>
    </profile>
    <profile>
        <id>beta</id>
        <build>
            <resources>
                <resource>
                    <directory>src/main/profiles/beta</directory>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                    </includes>
                    <filtering>true</filtering>
                </resource>
            </resources>
        </build>
    </profile>
    <!--此处省略其他环境配置-->
</profiles>

使用:

mvn clean package -Pdev -P就是说激活dev profile

mvn clean process-resources -Pbeta,会激活beta profile,此时,直接到target/classes下面验证。

maven的archetype模板

介绍:

artchetype其实就是个maven项目模板,用于生产maven项目的。

比如:我们使用idea创建maven项目时,自动创建的maven工程就是用的maven-archetype-quickstart模板,给我们创建好了最基础的工程结构和pom信息。

已有的Archetypes:

Archetype ID说明
maven-archetype-archetype一个样例原型
maven-archetype-j2ee-simple简单的J2EE应用程序样例
maven-archetype-mojoMaven插件样本的示例
maven-archetype-pluginMaven插件样本
maven-archetype-plugin-siteMave插件网站的样例
maven-archetype-portletJSR-268门户样例
maven-archetype-quickstartMaven工程样例
maven-archetype-simple一个简单的Maven工程
maven-archetype-siteMaven网站的样例,它演示了对诸如APT、XDoc和FML等文档类型的支持,并演示了如果把网站国际化(i18n)
maven-archetype-site-simpleMaven网站样例
maven-archetype-webappMaven的Webapp工程样例

自己写一个archetype:

1、创建archetype模板项目:

使用eclipse提供的向导,常见一个maven工程,选择的archetype是maven-archetype-archetype,就是用来创建archetype的一个模板。我在idea中没有找到maven-archetype-archetype这个archetype。

也可以在idea或者项目目录下输入命令行mvn archetype:create-from-project,会在项目目录下创建archetype,target/generated-sources/archetype就是想要的内容了。注意:一定要有一个maven项目。

可能运行过程中出现下面的错误:

image-20201206204222925

该问题是由于用户的.m2目录下缺少maven的配置文件,添加该配置文件后,命令正常执行。用户的.m2目录下maven的setting.xml文件是maven的一个规范,要把setting.xml文件放在此目录下面。

下面的图片就成功啦:

成功之后的文件路径:

image-20201206204622684

2、修改模板的pom.xml

archetype自己也需要一个pom.xml,用来定位自己的坐标。

在target/generated-sources/archetype目录下修改src/main/resouces/archetype-resources/pom.xml文件(groupid、artifactid、version等内容。注意:这里的内容才是项目所引用的pom的文件!)。

<groupId>com.wmm.maven.archetypes</groupId>
<artifactId>archetype-test</artifactId>
<version>1.0.0</version>
3、修改要生成的项目的pom.xml

编写src/main/resources/archetype-resources/pom.xml,这个就是要生成项目的pom.xml。

注意:里面要用到一些占位符,因为生成项目的时候,groupId和artifactId之类的都是用户输入的。里面可以放入任何你需要的依赖和插件。

image-20201206205835513

修改内容示例:

<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/maven-v4_0_0.xsd">
  	
  	<modelVersion>4.0.0</modelVersion>
  	
  	<artifactId>${project.artifactId}</artifactId>
  	<packaging>jar</packaging>
  	
  	<parent>
  		<groupId>com.wmm.test</groupId>
  		<artifactId>test</artifactId>
  		<version>${testVersion}</version>
  	</parent>
  	<name>${project.artifactId}</name>
  	<url>http://maven.apache.org</url>
  	<properties>
    	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  	</properties>
  	
  	<distributionManagement>
		<repository>
			<id>nexus-releases</id>
			<name>Nexus Release Repository</name>
			<url>http://localhost:8081/repository/maven-releases/</url>
		</repository>
		<snapshotRepository>
			<id>nexus-snapshots</id>
			<name>Nexus Snapshot Repository</name>
			<url>http://localhost:8081/repository/maven-snapshots/</url>
		</snapshotRepository>
	</distributionManagement>
  	
  	<dependencies>
		<!-- 依赖们 -->
  		<dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-core</artifactId>  
        </dependency>
  	</dependencies>
  	
  	<build>
  		<resources>
  			<resource>
  				<directory>src/main/java</directory>
  				<includes>
  					<include>**/*.xml</include>
  				</includes>
  				<filtering>true</filtering>
  			</resource>
  		</resources>
  		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-source-plugin</artifactId>
				<executions>
					<execution>
						<id>attach-sources</id>
						<phase>verify</phase>
						<goals>
							<goal>jar-no-fork</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<outputDirectory>${project.build.outputDirectory}</outputDirectory>
				</configuration>
			</plugin>
		</plugins>
  	</build>
  	
  	<profiles>
  		<!-- 每个profile对应了一个环境下的一套配置 -->
		<profile>
			<id>dev</id>
			<activation>
				<activeByDefault>true</activeByDefault>
			</activation>
			<build>
				<resources>
					<resource>
		  				<directory>src/main/profiles/dev</directory>
		  				<includes>
		  					<include>**/*.xml</include>
		  					<include>**/*.properties</include>
		  				</includes>
		  				<filtering>true</filtering>
		  			</resource>
				</resources>
			</build>
		</profile>
        <!--省略其他环境-->
	</profiles>
</project>

4、定义archetype的元数据

编写src/main/resources/META-INF/maven/archetype-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor name="archetype-oa">
	<fileSets>
        <!--filtered参数表示是否对文件启用占位符替换 packaged表示是否将文件放到包路径下 -->
		<fileSet filtered="true" packaged="true">
			<directory>src/main/java</directory>
			<includes>
				<include>**/*.java</include>
			</includes>
		</fileSet>
		<fileSet filtered="true" packaged="true">
			<directory>src/test/java</directory>
			<includes>
				<include>**/*.java</include>
			</includes>
		</fileSet>
		<fileSet filtered="true" packaged="false">
			<directory>src/main/resources</directory>
			<includes>
				<include>**/*.properties</include>
				<include>**/*.xml</include>
			</includes>
		</fileSet>
		<fileSet filtered="true" packaged="false">
			<directory>src/main/profiles/dev</directory>
			<includes>
				<include>**/*.properties</include>
				<include>**/*.xml</include>
			</includes>
		</fileSet>
		<fileSet filtered="true" packaged="false">
			<directory>src/main/profiles/beta</directory>
			<includes>
				<include>**/*.properties</include>
				<include>**/*.xml</include>
			</includes>
		</fileSet>
		<!--省略其他环境-->
	</fileSets>
	<requiredProperties>
		<requiredProperty key="testVersion" />
		<requiredProperty key="shortName" /> 
	</requiredProperties>
</archetype-descriptor>

文件的作用:

  1. 定义将这个archetype中的哪些java代码和测试代码以及资源文件,都包含到创建好的项目中去;

  2. 定义创建项目的时候需要输入的参数是什么。即占位符的值。

    默认情况下,会要求输入groupId,artifactId,version,package,也可以自己额外定义要求输入的参数,都可以在资源文件或者代码中使用${}的占位符方式来引用。

参数解读:

其中 filtered 参数表示是否对文件启用占位符替换, packaged 表示是否将文件放到包路径下。因为package是创建项目的时候必须输入的,就是你的包基础路径。一般是需要将代码放到包路径下的,而资源文件不需要放到包路径下。

5、编写要给新项目的java代码、测试代码以及资源包和配置文件

src/main/java,对应的目录是src/main/resources/archetype-resources/src/main/java子目录中的代码,在这里可以写你要预先给好的java代码

src/test/java,对应的目录是src/main/resources/archetype-resources/src/test/java子目录中的代码,就是你预先给好的测试代码

src/main/resources之类的,对应的目录是src/main/resources/archetype-resources/src/main/resources目录,在这里给好你预先包含的配置文件

同时对于你写的一些基础的类,一般是可以用package占位符的,到时候创建出来就会替换package。比如:

package ${package};
public class Application {

}
6、部署arthcetype到私服

mvn clean deploy安装到本地仓库和私服

7、用archetype创建一个工程

也可以使用mvn archetype:generate -DarchetypeGroupId=com.wmm.maven.archetypes -DarchetypeArtifactId=archetype-test -DarchetypeVersion=1.0.0 命令进行生成项目。

8、archetype catalog

也可以做到不需要输入archetype的坐标就可以使用,就是要将archetype加入一个archetype列表供用户选择,这个archetype列表就是在archetype-catalog.xml文件中。

maven默认会从几个地方去读取archetype-catalog.xml的内容:

  1. internal:maven-archetype-plugin内置了几十个archetype
  2. local:从~/.m2/archetype-catalog.xml读取,默认不存在,要自己创建
  3. remote:读取maven中央仓库的archetype-catalog.xml,大概有几百个archetype
  4. file:读取本机任何一个文件
  5. http:读取任何一个网络上的文件

默认maven会从local+remote去读取archetype列表供选择。

可以用mvn archetype:crawl来自动化扫描本地仓库中的archetype,然后生成一份archetype-catalog.xml放在~/.m2/目录下,但是一般不用这种方式。

idea中的配置方式:

修改idea archetype配置文件,默认是C:\Users\user.IntelliJIdea15\system\Maven\Indices\UserArchetypes.xml,写入自己的archetype的groupid等内容(此外,idea删除自定义的archetype也是通过修改这个文件即可)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值