百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

我在工作中是这样使用Maven的,你怎么用?

sinye56 2024-12-14 15:02 5 浏览 0 评论

推荐学习

前言

这次来说说maven这玩意,同样还是那句话,maven对我而言只是工具,一些常规操作已经足够了,有空有兴趣才会去深入研究它。接下来会记录下自己使用maven时需要注意和理解的地方,至于那些基本概念和环境配置的问题,相信大家都懂。

仓库

maven仓库可分为本地仓库和远程仓库。

如果公司自己有搭建maven私服,那么还可以细分为本地仓库、私服仓库(内网)、中央仓库(外网)。

私服是指公司内网搭建的maven仓库,可供公司内部人员使用。

pom.xml里依赖jar包的寻找流程:

  1. 本地仓库找,找到直接用,不需要联网。
  2. 本地找不到,私服仓库找,找到就下载到本地,以供下次直接使用。
  3. 私服找不到,会直接去中央仓库找,然后下载到私服、本地,以供下次直接使用。

没私服的话,本地仓库找不到就直接去中央仓库找。

构建过程

maven构建过程的各个环节,代表maven工作的某个阶段

  1. 清理:将以前编译得到的旧的class字节码文件删除,为下一次编译做准备。
  2. 编译:将Java源程序编译成class字节码。
  3. 测试:自动测试,自动调用junit程序。
  4. 报告:测试程序执行的结果。
  5. 打包:动态Web工程打war包,java工程打jar包。
  6. 安装:将打包得到的文件复制到仓库中指定位置。
  7. 发布:拷贝最终的工程包到远程仓库,以供其他开发人员使用。

maven实际工作时,顺序不一定从上到下。几个阶段是重要阶段,并不是maven的全部阶段。具体执行什么阶段,执行顺序是啥,依赖于它的生命周期。

有些文章会说到最后一个构建阶段:部署->将动态Web工程生成的war包复制到Servlet容器的指定目录下,使其运行。 这需要在tomcat这种servlet容器配置点什么,然后再执行maven相关命令,war包就会自动部署到容器下。不过我现在开发基本都是在SpringBoot环境下,war包部署就不存在了。有兴趣再去熟悉熟悉。

生命周期

三套相互独立的生命周期,互不影响,定义了构建环节的执行顺序。

  1. clean生命周期:构建之前进行一些清理工作。
  2. default生命周期:常用且核心,包括编译、测试、打包、安装、发布等
  3. site生命周期:生成项目报告、站点。发布站点。(我没怎么用过....)

依赖上述的构建过程和生命周期,maven执行任何一个阶段的时候,它前面的所有阶段都会执行。

例如我们执行 mvn install 的时候,代码会被编译,测试,打包。但不会clean(清理),因为install和clean是在不同的生命周期里,但我们可以结合使用,如:mvn clean install

idea内置maven界面也说明这一点,点击生命周期的某一个阶段,maven会把前面到此阶段都执行下,不信你可以试试。

maven命令

除了通过idea的界面操作maven,我们也可以手打命令,不然在linux系统上你怎么搞?

  • 清理 mvn clean
  • 编译 mvn compile
  • 测试 mvn test
  • 打包 mvn package
  • 安装 mvn install
  • 发布 mvn deploy

执行maven构建命令,必须在pom.xml所在的目录

根据maven生命周期,当你执行mvn install时, compile、test、package、intall会依次执行,mvn deploy同理。

实际开发中,我都是直接敲命令编译打包安装,用得最多的是

mvn clean install -Dmaven.test.skip=true -U

加上clean是先把文件清理干净,100%确保install后是最新修改的文件。

如果当前项目并不需要被任何其他项目依赖,就没必要install了,执行mvn clean package即可

mvn命令支持带参数

  • -U :该参数能强制让Maven检查所有SNAPSHOT依赖更新,确保集成基于最新的状态。
  • -Dmaven.test.skip=true :不执行测试用例,也不编译测试用例类。
  • -DskipTests :不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
  • -P : 多环境打包(后面会说)

插件

maven仓库除了保存jar包,还有插件。核心程序仅定义了抽象的生命周期,具体工作还是得由特定的插件来完成。

一般我使用maven-compiler-plugin 插件来编译,定义的jdk版本一定要跟你开发使用的jdk版本一致,不然后续打包会出错等各种奇怪问题。

pom.xml的build节点里

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

依赖范围

标识jar包能被管理的范围。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.3</version>
    <scope>compile</scope>
</dependency>
  • compile:依赖项目参与编译、测试、部署运行
  • test:仅参与测试,包括测试代码的编译、运行
  • provided:可以参与编译、测试,但打包不会引入

一张表格来总结

上述3个比较常见,还有另外3个不常见的

  • runtime:无需参与编译、后期测试和运行周期需参与,一般用于数据库驱动jar包
  • system:jar包从本地次磁盘路径拿,不用在maven仓库,一般加个systemPath节点表示具体路径
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.3</version>
    <scope>system</scope>
    <systemPath>../xx/xx.jar</systemPath>
</dependency>
  • import:导入另一jar包的东西,仅支持在<dependencyManagement>中定义(后续有例子)

注意:非compile的依赖不能传递!

打包方式

packaging节点里

<groupId>com.goku</groupId>
<artifactId>goku-manage</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
  • pom:依赖文件打包, 打出来可以作为其他项目的maven依赖,子工程继承父工程,子工程可直接使用父工程的配置,一般用在聚合工程来做jar包的版本控制。
  • jar:普通项目打包,开发时要引用通用类,打成jar包便于存放管理。SpringBoot内置tomcat,打成jar可直接运行。
  • war:web项目打包,打成war包部署到服务器。

聚合与继承

聚合工程里有多个pom.xml

父工程通过modules聚合子工程,该工程执行maven命令时,2个子工程也会执行

<modules>
    <module>goku-user</module>
    <module>goku-order</module>
</modules>

子工程通过parent标签继承父工程,可直接引用父工程的配置项

<parent>
    <groupId>com.goku</groupId>
    <artifactId>goku-manage</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

至于聚合模块的好处有很多,真真切切让我感受到的有其二

  1. 依赖包划分合理,职责结构清晰,不存在一个庞大的pom.xml。
  2. 内部代码改动后只需要编译当前工程,耗时减少。特别适合分布式项目。

统一版本号

聚合工程里,版本号可以统一配置,统一管理。同个公司的不同项目,所有依赖包版本最好相同。

有些公司会单独建一个工程,只用来统一版本号,打包成pom形式,给公司内部各个项目继承。

顶层父工程的pom文件里的properties节点

<properties>
    <java.version>1.8</java.version>
    <plugin.jdk.version>1.8</plugin.jdk.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-boot.version>2.1.3.RELEASE</spring-boot.version>
    <fasterjson.version>1.2.12</fasterjson.version>
</properties>

dependency的vesion引用配置好的版本号

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

dependencyManagement统一管理版本

请注意<scope>import</scope>

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.0.0.RELEASE</version>
            <type>pom</type>
            <!--导入spring-boot-dependencies里的配置,一定程度上解决了单继承问题。-->
            <scope>import</scope>
         </dependency>
         <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fasterjson.version}</version>
        </dependency>
     </dependencies>
 </dependencyManagement>

说明:

  1. dependencyManagement只是声明依赖,不会引入依赖。
  2. 子模块不会继承父模块中dependencyManagement所有预定义的depandency,若想使用还需引入需要的依赖,只不过不需要加version节点了。
  3. 据说在父模块中严禁直接使用depandencys预定义依赖,应该做到按需引入。

多环境打包

项目打包时区分环境,实际上是根据不同环境生成不同的配置文件。

一般区分本地、开发/测试、线上。

pom.xml里的build和profiles(以下配置仅针对SpringBoot的yml文件)

<build>
    <!-- 打包后文件名称:项目名-环境-版本 -->
    <finalName>${project.artifactId}</finalName>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <!-- 开启过滤替换功能-->
            <filtering>true</filtering>
            <includes>
                <!-- 项目打包完成的包中只包含当前环境文件 -->
                <include>application.yml</include>
                <include>application-${profileActive}.yml</include>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
    </resources>
</build>


<!-- 多环境配置方案 -->
<profiles>
    <profile>
        <id>local</id>
        <properties>
            <profileActive>local</profileActive>
        </properties>
        <activation>
            <!-- 默认情况下使用本地开发配置 如 打包时不包含 -p 参数-->
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>
    <!-- 打包命令package -P test -->
    <profile>
        <id>test</id>
        <properties>
            <profileActive>test</profileActive>
        </properties>
    </profile>
    <!-- 打包命令package -P prod -->
    <profile>
        <id>prod</id>
        <properties>
            <profileActive>prod</profileActive>
        </properties>
    </profile>
</profiles>

maven命令带参数-P,如:mvn clean install -P test

项目打包后只保留application.yml、ymlapplication-test.yml

application.yml里的@profileActive@也会被替换成test

最终打包生成的文件

setting.xml

localRepository

指定本地仓库地址,不配置就放在默认路径${user.home}/.m2/repository

<localRepository>D:\develop\maven\Repmaven</localRepository>

server

公司搭建了maven私服,上传下载需要认证,就需要配置。

NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are used together.

可配置账号密码 或 私钥形式,支持多个server

<servers>
    <server>
        <!--id需要与repository或mirror中的id相对应-->
        <id>server01</id>
        <username>admin</username>
        <password>SwaDmin159</password>
    </server>
    <server>
        <id>server02</id>
        <privateKey>/xxx/.ssh/id_dsa</privateKey>
        <passphrase>some_passphrase</passphrase>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
        <configuration></configuration>
    </server>
</servers>

mirror

仓库镜像,中央仓库的代理,如果配置了镜像,就直接去镜像中下载依赖。它相当于一个拦截器,拦截maven对默认中央仓库的请求,把请求里的远程仓库地址,重定向到mirror里配置的地址。

  <mirrors>
     <mirror>
         <id>nexus-aliyun</id>
         <mirrorOf>central</mirrorOf>
         <name>Nexus aliyun</name>
         <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
  </mirrors>

profile and activeProfiles

所有项目使用私服仓库,可在setting.xml配置,profile节点配置repositories,最后再激活profile。

当然,私服里不只一个仓库,可配置多个repository。

 <profile>
     <repositories>  
        <repository>  
            <!-- id需要与私服里仓库的id对应 -->
            <id>public</id>  
            <name>public</name>  
            <url>http://xxx.com/nexus/content/groups/public/</url>             
            <layout>default</layout>              
        </repository> 
    </repositories>  
</profile>

<activeProfiles>
    <activeProfile>public</activeProfile>
</activeProfiles>

若只想针对某个项目,则在当前项目的pom.xml配置私服,repositories节点下配置即可

<repositories>
    <repository>
        <!-- id需要与私服里仓库的id对应 -->
        <id>public</id>
        <name>public</name>
        <url>http://xxx.com/nexus/content/groups/public/</url>             
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

distributionManagement

有时我们自己开发的模块需要被其他部门的开发人员使用,就需要发布到私服。

执行mvn deploy前,需配置distributionManagement。

快照版本跟发布版本分别存储到不同仓库地址。

<distributionManagement>
    <repository>
        <id>release</id>
        <name>Project Release</name>
       <url>http://xxx.com/nexus/content/groups/release/</url>             
    </repository>
    <snapshotRepository>
        <id>snapshots</id>
        <name>Project SNAPSHOTS</name>
           <url>http://xxx.com/nexus/content/groups/snapshot/</url>      
    </snapshotRepository>
</distributionManagement>

快照版本vs发布版本

maven会根据jar包的版本号(version节点)是否带有-SNAPSHOT来判断是快照版本还是正式版本。没有SNAPSHOT都认为是快照版本。

快照版本 :1.0.0-SNAPSHOT

发布版本 :1.5.3.RELEASE

如果是快照版本,在mvn deploy时会自动发布到快照版本库中,覆盖老的快照版本,后面使用快照版本模块时,在不更改版本号的情况下,直接编译打包时,maven会自动从远程服务器上下载最新的快照版本。

如果是正式发布版本,在mvn deploy时会自动发布到正式版本库中,后面使用正式版本的模块,在不更改版本号的情况下,编译打包时如果本地已经存在该版本的模块则不会主动去远程服务器上下载。

这个也容易理解,快照版本一般定义为不稳定版本,需要实时更新。


作者:悟空GoKu
原文链接:https://juejin.im/post/5ef719805188252e53636058

相关推荐

linux 查看当前应用内存状况,以及内存参数含义

1、查看进程号ps-ef|greptomcat2、查看当前内存分配,200ms打印一次jstat-gc进程号2001jstat-gc344802001S0CS1C...

如何显示 Linux 系统上的可用内存?这几个命令很好用!

在Linux系统中,了解可用内存是优化系统性能、故障排查以及资源管理的重要一环。本文将详细介绍如何在Linux系统上显示可用内存,包括多种方法和工具的使用。在讨论可用内存之前,我们需要了解一些...

Linux 下查看内存使用情况方法总结

Q:我想监视Linux系统的内存使用情况,在Linux下有哪些视图或者命令行工具可用呢?在做Linux系统优化的时候,物理内存是其中最重要的一方面。自然的,Linux也提供了非常多的方法来监控宝贵的内...

2、linux命令-用户管理

linux命令-用户管理用户切换[root@eric~]#sueric#切换到用户eric[eric@ericroot]$[eric@ericroot]$su#切换到rootPas...

Centos 7 进入单用户模式详解

1、开机在启动菜单按e进入编辑模式找到linux16行,在最后添加init=/bin/sh编辑完后,按ctrl+x退出2、进单用户模式后,使用passwd修改密码,提示以下错误:passwd:Aut...

每日一个Linux命令解析——newusers

newusers:在Linux系统中,newusers是一个用于批量创建用户的命令。它从一个文件中读取多行用户信息,每行描述一个用户的详细信息,并根据这些信息创建多个用户或对现有用户进行批量修改。一...

openEuler操作系统管理员指南:管理用户与用户组

在Linux中,每个普通用户都有一个账户,包括用户名、密码和主目录等信息。除此之外,还有一些系统本身创建的特殊用户,它们具有特殊的意义,其中最重要的是管理员账户,默认用户名是root。同时Linux也...

Linux用户管理

1、用户信息文件/etc/passwdroot:x:0:0:root:/root:/bin/bash第一列:用户名第二列:密码位第三列:用户ID0超级用户UID。如果用户UID...

centos7基础-用户、组、权限管理

用户和组(1)用户、组、家目录的概念linux系统支持多用户,除了管理员,其他用户一般不应该使用root,而是应该向管理员申请一个账号。组类似于角色,系统可以通过组对有共性的用户进行统一管理。每个用户...

LINUX基础 ----------组及用户的概念

在Linux中,用户和组都是非常重要的概念,可以控制文件访问权限和资源的管理。用户是标识一个进程、应用程序或系统管理员的账号,Linux中每个用户用一个用户ID(UID)来标识。对于一个...

从零入门Linux(四)用户与权限管理

在Linux系统中,用户和权限管理是系统安全的重要组成部分。通过合理配置用户和权限,可以确保系统的安全性和资源的合理分配。以下是一些与用户和权限管理相关的常用命令和概念。1.用户管理1.1添加...

如何在 Linux 中管理用户?

在Linux系统中,用户是系统资源的主要使用者,每个用户都有一个唯一的标识符(用户ID)。为了更好地组织和管理用户,Linux还引入了用户组的概念。用户组是用户的集合,有助于更有效地分配权限和资...

在 Linux 中将用户添加到特定组的四种方法

在Linux多用户操作系统中,用户组管理是系统安全架构的基石。通过合理的组权限分配,管理员可以实现:精确控制文件访问权限(chmod775project/)简化批量用户权限管理(setfacl-...

我不是网管 - 如何在Ubuntu Linux下创建sudo用户

Sudo用户是Linux系统的普通用户,具有一定的管理权限,可以对系统执行管理任务。在Linux中,root是超级用户,拥有完全的管理权限,但不建议将root凭证授予其他用户或作为r...

Linux创建普通用户,为密钥方式登录做准备

Hi,我是聪慧苹果8,就是江湖上人见人爱、花见花开,土到掉榨的Linux爱好者,一起学习吧!上一篇关于SSH安全加固的文字,有网友点评通过密钥登录更加安全,先创建一个普通用户,拒绝直接使用密码登录,这...

取消回复欢迎 发表评论: