五、maven生命周期与插件机制
-
maven生命周期
maven共有三套生命周期,每套生命周期又由若干个phase组成,而每个phase的具体执行过程实际上是由不同的plugin的goal来完成,每个phase可以绑定一个或多个插件的一个或多个goal。maven在某些关键phase上已默认绑定了goal,这就是我们在默认的情况下也可以做一些事情的原因。
可以参考上边的图理解,生命周期和插件的关系
-
clean生命周期,做项目的清理工作,包含以下phase
pre-clean
clean
post-clean
-
default生命周期,做项目的编译测试发布打包等工作,包含以下phase
validate:校验这个项目的一些配置信息是否正确
initialize:初始化构建状态,比如设置一些属性,或者创建一些目录
generate-sources:自动生成一些源代码,然后包含在项目代码中一起编译
process-sources:处理源代码,比如做一些占位符的替换
generate-resources:生成资源文件,才是干的时我说的那些事情,主要是去处理各种xml、properties那种配置文件,去做一些配置文件里面占位符的替换
process-resources:将资源文件拷贝到目标目录中,方便后面打包
compile:编译项目的源代码
process-classes:处理编译后的代码文件,比如对java class进行字节码增强
generate-test-sources:自动化生成测试代码
process-test-sources:处理测试代码,比如过滤一些占位符
generate-test-resources:生成测试用的资源文件
process-test-resources:拷贝测试用的资源文件到目标目录中
test-compile:编译测试代码
process-test-classes:对编译后的测试代码进行处理,比如进行字节码增强
test:使用单元测试框架运行测试
prepare-package:在打包之前进行准备工作,比如处理package的版本号
package:将代码进行打包,比如jar包
pre-integration-test:在集成测试之前进行准备工作,比如建立好需要的环境
integration-test:将package部署到一个环境中以运行集成测试
post-integration-test:在集成测试之后执行一些操作,比如清理测试环境
verify:对package进行一些检查来确保质量过关
install:将package安装到本地仓库中,这样开发人员自己在本地就可以使用了
deploy:将package上传到远程仓库中,这样公司内其他开发人员也可以使用了
-
site生命周期,生成项目的说明文档网站,一般不怎么用,包含以下phase
pre-site
site
post-site
site-deploy
- 默认的phase和plug的绑定
maven为我们默认绑定一些plugin goal到phase上
-
clean生命周期的默认绑定
phase plugin goal clean clean:clean -
default生命周期的默认绑定
phase plugin goal process-resources resources:resources compile compiler:compile process-test-resources resources:testResources test-compile compiler:testCompile test surefire:test package jar:jar或者war:war install install:install deploy deploy:deploy -
site生命周期的默认绑定
phase plugin goal site site:site site-deploy site:deploy - maven的命令行和生命周期
理解不同的命令,具体执行什么样的生命周期
-
mvn clean install的理解
clean是指,clean生命周期的clean phase,使用此命令会执行clean生命周期包含clean这个phase前的所有phase,也就是pre clean和clean两个phase
instal是指,default生命周期的install phase,使用此命令会执行install phase及其前边所有phase,具体就不列举了,可以查看上边的default生命周期去了解
注意在执行过程中的phase如果未绑定具体的goal其实是不会做任何事情的,这些是为什么我们在需要执行某些特定的phase时手动添加plugin并绑定phase与具体的goal
-
mvn dependency:tree的理解
-
就是指直接执行dependency插件的tree这个goal,所以只会展示依赖树这一个目标
- maven插件管理和配置
-
插件和goal,每个插件都有多个goal,每个goal可以实现一个具体的功能
将插件的goal与phase绑定,具体是在pom.xml加如下配置
-
<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>
</plugin>
</plugins>
</build>
注意以上配置中的phase与goal,绑定后运行mvn verify,就可以看到生成了一个包含源码的jar包
* 插件参数设置,在命令行执行时-Dkey=value来设置
比如常见的mvn install -Dmaven.test.skip=true就是surefire插件在测试的时候提供的参数,设置为true就会跳过测试
也可以在pom中通过<configuration>标签做配置
<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>
* 插件地址 [http://maven.apache.org/plugins/index.html](http://maven.apache.org/plugins/index.html)
* 插件仓库,maven默认已配置,但我们在前边已修改为从私服下载
六、多模块依赖与版本号约束
-
构建基于聚合工程的多模块项目
先看一个配置,父工程pom文件
<groupId>com.pxjy.ti.hummingbird</groupId> <artifactId>hummingbird-boot</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>hummingbird-boot</name> <modules> <module>../hummingbird-data</module> <module>../hummingbird-wing</module> <module>../hummingbird-arrange</module> <module>../hummingbird-erpbase</module> <module>../hummingbird-common</module> </modules>
再看子工程pom文件
<parent> <groupId>com.pxjy.ti.hummingbird</groupId> <artifactId>hummingbird-boot</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../hummingbird-boot/pom.xml</relativePath> </parent>
- 这种方式的配置是创建一个父项目,里边只有一个pom文件,packaging方式为pom,通过modules定义子工程及其相对路径
- 子工程pom文件中使用parent标签引用父项目
- 父pom中指定对于所有项目都需要的公共依赖
- 子工程强制继承父pom中的依赖并添加自己需要的依赖
-
强制统一版本的多模块继承
一个问题:由于以上方案非强制,可能不同的模块开发负责人会在自己模块里随意引入同一个包的不同版本导致集成的时候出问题
- 更好的做法是统一在父工程中管理所有依赖和插件,子工程按需申明,父pom使用如下配置
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot</artifactId> <version>2.1.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.1.9.RELEASE</version> </dependency> <dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>test-compile</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> <configuration> <jvmTarget>${java.version}</jvmTarget> <javaParameters>true</javaParameters> </configuration> </plugin> <pluginManagement> </build>
子工程中使用依赖和插件时不需要再定义版本号,直接按需引用即可
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
-
集中约束版本号配置
<!--配置--> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR3</spring-cloud.version> <apollo.version>1.4.0</apollo.version> </properties> <!--使用--> <dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>${apollo.version}</version> </dependency>
-
使用import pom强制约束依赖方版本号
场景:你开发的包提供给第三方使用,你的包会依赖一些其他jar包,为防止第三方项目中使用其他jar包的低版本,导致问题,需要对相关jar包都做版本限制
首先单独编写一个xx-bom工程,类型为pom,在工程的pom文件中使用dependencyManagement标签指定你的包和重要第三方包的版本号
-
使用你的jar包的第三方通过如下方式使用,注意type和scope
<dependencyManagement> <dependencies> <dependency> <groupId>com.xx.xxx</groupId> <artifactId>xx-bom</artifactId> <version>1.2.9</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
七、基于profile的资源配置与打包
-
背景
每个项目从开发到上线大概会经历dev、beta、test、staging、prod等不同的阶段,每个阶段都对应着不同的配置,每次发布到不同的环境是都需要手动修改配置,变更麻烦,容易发生错误
-
简单解决方案
- 在项目src/main/resources目录下使用占位符对配置文件配置
- 在pom文件中使用profiles标签,不同环境对应不同的配置,一般会默认激活一个profile
<profiles> <profile> <id>local</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <database.jdbc.driverClass>com.mysql.jdbc.Driver</database.jdbc.driverClass> <database.jdbc.connectionURL>jdbc:mysql://192.168.31.110:3306/oa_local <database.jdbc.connectionURL>jdbc:mysql://192.168.31.110:3306/oa_local </database.jdbc.connectionURL> <database.jdbc.username>local</database.jdbc.username> <database.jdbc.password>local</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://192.168.31.110:3306/oa_dev </database.jdbc.connectionURL> <database.jdbc.username>dev</database.jdbc.username> <database.jdbc.password>dev</database.jdbc.password> </properties> </profile> </profiles>
-
指定maven resources插件资源处理路径
<resources> <resource> <directory>${project.basedir}/src/main/resources</directory> <!--filtering为true代表自动替换资源文件中的占位符--> <filtering>true</filtering> </resource> </resources> <testResources> <testResource> <directory>${project.basedir}/src/test/resources</directory> <filtering>true</filtering> </testResource> </testResources>
使用命令mvn clean package -Ptest,-P就是说激活test profile,完成test环境打包
-
通用解决方案
原因:大型项目的配置会很多,都在pom.xml里配置会让pom.xml文件很大也很混乱
-
在工程里直接创建如下目录,存放不同环境的配置
src/main/profiles/dev
src/main/profiles/beta
src/main/profiles/test
src/main/profiles/staging
src/main/profiles/prod
-
在每个profile的配置里,直接配置资源文件打包的目录
<build> <resources> <resource> <directory>src/main/profiles/dev</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
使用mvn clean process-resources -Pdev激活各个profile
-
八、生成自己企业项目的工程骨架
简单说明一下大概步骤,这一块一般不怎么使用,需要的时候再详细查找
-
创建maven-archetype项目,使用工程骨架选maven-archetype-quickstart,如果是web项目选
maven-archetype-webapp
-
定义archetype工程项目坐标
<groupId>com.xxxx.maven.archetypes</groupId> <artifactId>maven-archetype-parent</artifactId> <version>1.0.0</version>
-
编写待生成项目的pom.xml,路径在src/main/resources/archetype-resources/pom.xml,项目坐标采用占位符方式,待项目生成时输入
<groupId>${groupId}</groupId> <artifactId>${artifactId}</artifactId> <version>${version}</version> <name>${artifactId}</name> <!--下面可以直接指定部分依赖-->
定义项目元数据src/main/resources/META-INF/maven/archetype-metadata.xml
<?xml version=”1.0” encoding=”UTF-8”?>
<archetype-descriptor name=”parent”>
<fileSets>
<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=”true”>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
</includes>
</fileSet>
</fileSets>
<requiredProperties>
<requiredProperty key=”port” />
<requiredProperty key=”groupId”>
<defaultValue>com.xxxx</defaultValue>
</requiredProperty>
</requiredProperties>
</archetype-descriptor>
- 编写项目的代码、测试代码、资源文件等,可通过占位符输入包名
package ${package}
public class Application {
}
部署到私服mvn clean deploy
-
使用archetype生成工程
mvn archetype:generate -DarchetypeGroupId=com.zhss.archetypes -DarchetypeArtifactId=archetype-oa -DarchetypeVersion=1.0.0