maven 实战

 

主要解决问题
 
jar 包冲突,项目臃肿不堪
 
何为构建
编译、单元测试、生成文档、打包、部署等等
 
Maven是优秀的一键构建软件
Maven还是一个依赖管理、项目信息管理软件
 
编写 POM
Maven项目的核心是 POM.XML,POM(Project Object Model项目对象模型)定义了项目的基本信息,用来描述项目如何构建,声明项目依赖等等。
 
 
<groupId>com.csii.loan</groupId>
<artifactId>csii-loan-parent</artifactId>
<version>1.0</version>
 
groupId 、artifactId、version 三行元素定义了一个项目基本的坐标,在 Maven世界,任何的 jar、pom和 war 都是基于这些基本坐标进行区分的。
 
groupId 定义了项目属于哪个组,这个项目往往和公司或者组织存在关联。artifactId 定义了当前 Maven 项目在组中唯一的ID ,Hello-Word项目定义了 hello-word ID。version定义了当前项目的版本。
 
在绝大数情况下,应该把项目的主代码放到 src/main/java 目录下 ,maven 会自动搜寻该目录找到项目主代码。
 
 mvn clean   —   会清除目录  target/ 
 mvn  compile  —  告诉maven编译项目的主代码
 
 
 
scope 为依赖范围,若依赖范围为 test  ,则表示该依赖只对测试有效。如果不声明依赖范围,那么默认值就是 compile,表示对主代码和测试代码都有效。
 
打包和运行
将项目进行编译和测试后,下一个重要的步骤就是打包(package),pom中没有指定打包类型,使用默认打包类型 jar
 
如何才能让 maven 项目直接引用这个 jar ?
install 将项目输出的 jar 安装到 Maven本地仓库中,可以打开相应的文件夹看到项目的 pom 和 jar ,只有构建被下载到本地仓库后,才能由所有的maven 项目使用。
 
这个仓库 会不会越来越臃肿?
 
使用 Archetype 生成项目骨架
在项目的根目录建立 pom.xml ,在 src/main/java 目录放置项目的主代码,在 src/test/java 中放置项目的测试代码 等等 ,这个就是项目的骨架
 mvn archetype : generate   生成项目的骨架。 
 
坐标和依赖
 
何为坐标?
坐标为构件引入秩序,任何一个构件都要明确定义自己的坐标,而这些坐标是通过元素定义的。
  
当我们开发项目的时候,也要为其定义适当的坐标,这样其他的项目才能引用该项目生成的构件。
 
1、groupId  定义了项目隶属的组织
2、artifactId  推荐的做法是使用实际项目名称作为前缀
3、version 
4、packaging  定义了 maven 项目的打包方式 ,默认 jar ,可以 war 、pom等。
5、classifier
 
 maven中的仓库分为两种,snapshot快照仓库和release发布仓库。snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本。
 
定义一个组件/模块为快照版本,只需要在pom文件中在该模块的版本号后加上-SNAPSHOT即可(注意这里必须是大写),如下:
<groupId>cc.mzone</groupId>
<artifactId>m1</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
 
依赖的配置
 
dependencies 可以包含一个或者多个 dependency 元素 ,以声明一个或者多个项目依赖,每个依赖包含的元素有:
 
groupId、artifactId、version  — 依赖的基本坐标,对任何一个依赖来说,非常重要。
type  — 依赖的类型,对应项目坐标定义的 packaging ,大部分情况下,该元素不必声明。
scope 依赖的范围
optional 标记依赖是否可选
exclusion 用来排除传递性依赖
 
依赖的范围
 
maven 项目编译主代码的时候使用的是一套 classpath ,测试主代码的时候是另一套classpath
 
依赖范围就是用来控制这种 classpath 的关系 (编译 classpath、测试 classpath、运行classpath )
 
1、compile   编译依赖范围,默认使用它,编译、测试、运行三种 classpath都有效
2、test   测试依赖范围,只对测试的 classpath 有效
3、provided  已提供依赖范围,对于编译、测试 classpath 有效,运行时4、classpath无效,比如说 servlet-api 编译测试时需要依赖,但是运行时不需要,因为已经存在咯。
??5、runtime 运行时依赖范围,编译时主代码无效
6、system 
 
 
传递性依赖
 
有了传递性依赖,在使用时候就不用考虑 它依赖了什么 ,也不用担心引入了多余的依赖。
maven 会解析各个直接依赖的 pom ,将那些必要的间接依赖以传递性依赖的形式引入当前的项目中。
 
A依赖B,B依赖C,A对C就形成了传递性依赖
 
依赖调解
 
A——》B——》——》C——》X(1.0)
A——》D——》X(2.0)
 
两个版本的X ,都被加载肯定是不对的,依赖重复了。
这里第一原则:选择路径最近的优先。
如果路劲一样长呢,这里选择第二原则:第一声明者优先。
 
可选依赖
 
 
 
<optional> 表示 mysql-connector-java 和 postgresql  这两个依赖为可选择依赖,他们只对当前的项目 B 产生影响 ,如果其他的项目A依赖这个项目B 。那么 mysql-connector-java 和 postgresql   不会被传递。
 
但是项目 A 一定要使用 mysql-connector-java 呢? 那就在项目A 的 pom 文件中重新定义一个 mysql-connector-java 依赖。
 
使用可选依赖的原因是某个项目实现了多个特性,但是 java 设计思想就是一个类 ,一种对应的职责 , 所有对于可选依赖最好的解决办法就是 mysql-connector-java 和 postgresql 分别建立 maven 项目。
 
排除依赖
 
 
项目A 依赖 项目B,但是由于一些原因,不想引入传递性依赖C,而是自己显示的声明正式版C 1.0 ,所以代码使用  exclusions 排除不需要的依赖。
 
 
 
<!-- PE依赖jar -->
<dependency>
   <groupId>com.csii.pe</groupId>
   <artifactId>pe-core</artifactId>
   <version>${csii.pe.version}</version>
   <exclusions>
      <exclusion>
         <groupId>org.javassist</groupId>
         <artifactId>javassist</artifactId>
      </exclusion>
      <exclusion>
         <groupId>javassist</groupId>
         <artifactId>javassist</artifactId>
      </exclusion>
   </exclusions>
</dependency>
 
 
归类依赖
 
 
 
使用常量,不仅仅让代码更简洁,更重要的是可以避免重复,在需要修改时 ,改一处就好了。
 
 
<properties>
   <!-- 制定文件编码 -->
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <!-- 相关软件版本号 -->
   <commons-lang.version>2.6</commons-lang.version>
   <collections4.version>4.1</collections4.version>
   <spring.version>4.3.4.RELEASE</spring.version>
   <csii.pe.version>10.0.1</csii.pe.version>
   <dubbo.version>2.8.4a</dubbo.version>
   <servlet.version>3.1.0</servlet.version>
   <solrj.version>6.3.0</solrj.version>
   <zookeeper.version>3.4.8</zookeeper.version>
   <jackson.version>2.8.5</jackson.version>
   <kryo.version>3.0.3</kryo.version>
   <slf4j.version>1.7.21</slf4j.version>
   <logback.version>1.1.7</logback.version>
   <tomcat-jdbc.version>8.5.4</tomcat-jdbc.version>
   <spring-ibatis.version>2.0.8</spring-ibatis.version>
   <ibatis-sqlmap.version>2.3.4.726</ibatis-sqlmap.version>
   <elasticsearch.version>2.3.4</elasticsearch.version>
   <fastjson.version>1.2.27</fastjson.version>
   <flowctrl.version>1.1.1</flowctrl.version>
   <disconf.version>2.6.36</disconf.version>
   <http.core.version>4.4.6</http.core.version>
   <mybatis.spring.version>1.3.1</mybatis.spring.version>
   <mybatis.version>3.4.5</mybatis.version>
   <mybatis-paginator.version>1.2.17</mybatis-paginator.version>
   <druid.version>1.1.6</druid.version>
   <mysql.version>5.1.40</mysql.version>
   <mybatis.generator.version>1.3.5</mybatis.generator.version>
   <lombok.version>1.16.2</lombok.version>
   <activiti.version>5.22.0</activiti.version>
   <hibernate.version>4.2.5.Final</hibernate.version>
   <guava.version>17.0</guava.version>
   <junit.version>4.12</junit.version>
   <loan.sys.version>2.0.1</loan.sys.version>
   <loan.schedule.version>1.0.3</loan.schedule.version>
</properties>
 
 
 
<dependency>
   <groupId>com.csii.loan</groupId>
   <artifactId>csii-loan-schedule-core</artifactId>
   <version>${loan.schedule.version}</version>
</dependency>
 
<!--依赖的系统模块-->
<dependency>
   <groupId>com.csii.loan</groupId>
   <artifactId>csii-loan-sys-service</artifactId>
   <version>${loan.sys.version}</version>
</dependency>
<dependency>
   <groupId>com.csii.loan</groupId>
   <artifactId>csii-loan-sys-model</artifactId>
   <version>${loan.sys.version}</version>
</dependency>
 
首先使用了 properties 定义了 maven 属性,在具体的依赖中使用了 ${ properties节点名 } 定义版本 version 
 
优化依赖
 
程序员也应该能够对 Maven 项目了然于胸,并对其进行优化,排除多余的依赖,显示的声明某些必要的依赖。
 
Maven 会自动解析所有项目的直接依赖和传递性依赖,并根据规则正确判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构件只有唯一的版本在依赖中存在。
 
使用 dependency : list 和 dependency :tree 可以帮我们详细了解项目中所有依赖的具体信息。在此基础上,通过 dependency : analyze 分析项目的依赖。
 
 
仓库
 
何为仓库?
 
在 maven 世界中,任何一个依赖、插件或者项目构建的输出,都可以称为一个构件,任何一个构件都有一组坐标唯一标识。
 
Maven 可以在某个位置统一存放所有的 maven 共享构件,在项目中只要声明这些依赖的坐标,需要的时候会 跟据 classpath 自动使用它们。
 
 
仓库的布局
 
任何一个构件都有唯一的一个坐标,根据这个坐标可以定义唯一的存储路径。
 
仓库的分类
 
 
<distributionManagement>
   <repository>
      <id>central</id>
      <name>gitlab-svr.csii.com.cn-releases</name>
   </repository>
   <snapshotRepository>
      <id>snapshots</id>
      <name>gitlab-svr.csii.com.cn-snapshots</name>
   </snapshotRepository>
</distributionManagement>
 
在 repositories 元素下,可以使用一个或者多个 repository 子元素声明一个或者多个远程仓库。
 
配置中的  releases 和 snapshots 元素比较重要,用来控制 maven 的发布控件和快照构件的下载
 
???快照版本
在 maven 世界中,任何一个项目或者构件都有一个版本
 
2.1-SNAPSHOT-时间戳
项目不应该依赖任何组织外部的快照版本依赖
,由于快照版本的不稳定性,这样的依赖会造成潜在的风险,今天是这个快照,明天又是另一个快照咯。
 
 
生命周期和插件
何为生命周期?
 
几乎所有的项目构建,都会映射到这样的一个生命周期上。
 
 
当用户有特殊需要的时候,也可以配置插件定制构件行为,甚至自己编写插件。
 
 
三套生命周期?
 
Maven 拥有三套相互独立的生命周期,分别是 clean  default  site
 
clean 生命周期用于清理项目
default   生命周期用于构建项目
site 生命周期用于建立项目站点
 
     mvn clean
     mvn test
     mvn clean install
 
??插件的绑定
 
Maven 的生命周期与插件相互绑定,用于完成实际的构建任务。
 
具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。
 
 
 
聚合和继承
 
软件设计人员往往采用各种方式对软件划分各种模块,以得到更清晰的设计及更高的重用性。
 
聚合
 
我们想要一次构建两个项目,而不是到两个模块目录下分别执行 mvn 命令, Maven聚合就是为该需求服务的。
 
<modules>
   <module>csii-loan-mgmt</module>
   <module>csii-loan-mgmt-credit</module>
   <module>csii-loan-common-credit</module>
</modules>
 
Maven 会首先解析聚合模块的 POM 、分析要构建的模块、并计算出一个反应堆构建顺序(Reactor Build Order),然后根据这个顺序依次构建各个模块。
 
继承
 
在父类声明一些字段和方法供子类继承,“一处声明,多处使用”。
 
 
<parent>
    <artifactId>csii-loan-common-credit</artifactId>
    <groupId>com.csii.loan</groupId>
    <version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
 
<artifactId>csii-loan-common-anno</artifactId>
<version>1.0</version>
<name>csii-loan-common-anno</name>
 
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
 
在子类中首先声明 <parent> 标签,然后才是自己的 <artifactId> 和 
<version>
 
??依赖管理
 
Maven 提供的 dependencyManagement
既能让让子模块继承父模块的依赖配置,又能保证子模块依赖使用的灵活性
 
??插件管理
 
pluginManagement
 
 
聚合和继承的关系
 
对聚合模块而言,它知道有哪些聚合模块,但是哪些聚合模块不知道这个聚合模块的存在。
 
对于继承的父 pom 而言,它不知道哪些子模块继承它,但是子模块都知道这个父 pom 
 
共同点就是 聚合 pom 和 父pom 的packing 都必须是 pom 格式。
 
 
但是实际项目中 ,一个 pom 即是聚合 pom ,又是 父 pom 
 
“约定优于配置”
 
使用约定可以大大减少配置
 
 
 
 
 
 
Ant 的配置相当的多,
但是maven 只有短短的几行 ,剩下的只要按照约定目录建造就好。
 
反应堆
 
在一个多模块的maven 项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。
对于单模块项目而言,反应堆就是该模块本身
对于多模块项目来说,反应堆包含各个模块之间的继承和依赖关系,从而计算出合理的模块构建顺序。
 
实际的构建顺序是这样形成的
Maven 按照顺训读取 pom  ,如果该 pom 没有依赖模块,那么就先构建其模块;如果有依赖模块,那么先构建依赖模块;还有依赖,就构建依赖的依赖模块。
 
模块间的依赖关系,将反应堆构成了一个有向非循环依赖,如果 A 依赖 B , B 依赖 A  , maven 就会报错。
 
使用 maven 进行测试
 
随着敏捷开发的日益流行,软件开发人员也越来越认识到日常编程中单元测试的重要性。
 
 
 
使用 Hudson 持续集成
 
 
 
 
使用 MAVEN 构建 web 项目
 
基于 java 的 Web 项目,标准的打包方式是 war 包。war 包和 jar 包 类似,只不过包含更多的内容, 主要的两个子目录:
 Meta-inf 和 web - inf 
 
maven必须为 web项目显示的指示打包方式为 war 
 
 
 
 
 
 
版本管理
 
 
称稳定的版本为发布版,如果项目进入下一个开发阶段,自然又转为一个新的快照版本。
 
版本管理最关心的就是 快照版本和稳定版本之间的转换。
 
1、3、4 — beta — 2
 
 
 
灵活的构建
 
 
一个优秀的构建 系统必须足够灵活,能够让项目在不同的环境下都能成功的构建。
 
Maven 属性
 
 
构建环境的差异
 
在 src / mian / resources 目录下的配置 连接数据库的操作。
 
 
资源过滤
 
使用 maven 资源将这些经常变化的部分提取出来,
 
 
生成项目的站点
 
 
 
 
 
编写maven插件
 
maven的任何行为都是可以通过插件完成的,包括项目的清理、编译、测试和打包等操作都有对应的 maven插件。每个插件都有一个或者多个目标。
 
 
 
Archetype
 
使用它快速生成项目的 骨架 ,可以将其理解为maven 项目的模版,只要提供最基本的元素,就能生成基本结构和 pom 文件。
 
当然可以自己构建通用项目结构。 
 
 
 
 
 
 
 
 
 
 
 
 

 

posted @ 2021-12-21 21:51  养柱  阅读(131)  评论(0)    收藏  举报