工程规约 - maven 统一管理
一、前言
事情是这样的:最近条线内部在搞“避免重复造轮子”的整改活动。其中发生了一个事情,之前条线内部的A团队已经尝鲜使用了XXL-job,后面考虑到避免重复造轮子,就要求B团队新建的系统也统一使用XXL-job,然后通过执行器进行权限管理,最后才发现原来A团队使用的那个版本还没有支持权限管理。从这里,我发现到一个问题:我们的maven管理确实很混乱,依赖版本管理必须得统一管理起来。
二、一团糟
实际上,日常工作中还有其他问题的:
“天啊,投产包为什么会是SNAPSHOT版本?”“哪位潇洒的大侠居然引用了一个快照版的三方包?坑爹啊”“我去,生产爆了个大bug,为什么你们系统没有?噢,原来我们用的版本不一样,你真幸运。”
以上的问题如何解决呢?其中一个答案就是:
统一我们的父pom【根】,然后要求所有团队的项目直接使用这个【根】或者再基于这个【根】进行继承成自己项目的二级父pom,通过这个二级父pom进行版本管理。
三、如何利用父pom
1、对于某些基础包进行统一版本管理。这样的话,当子pom引用的使用就只需要groupId和artifactId即可,且当父pom的版本一改,所有子pom就会统一自动继承。
<properties>
<java.version>1.8</java.version>
<maven.version>3.3.7</maven.version>
<mybatis.version>2.1.2</mybatis.version>
<enforcer.version>1.4.1</enforcer.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
2、在父pom加入maven-enforcer-plugin进行规则校验。
之前在DevOps meetup上面京东数科DevOps落地实践的线上分享中提过他们的流水线上也会用到maven-enforcer-plugin。后面做了简单的试验并结合团队的实际情况,建议我们主要用以下几个校验规则。
requireMavenVersion - enforces the Maven version.
requireJavaVersion - enforces the JDK version.
requireReleaseVersion - enforces that the artifact is not a snapshot.
banDuplicatePomDependencyVersions - enforces that the project doesn't have duplicate declared dependencies.
requireReleaseDeps - enforces that no snapshots are included as dependencies.
bannedDependencies - enforces that excluded dependencies aren't included.
这里以我的其中一个项目父pom作为例子,里面存着以上头4个问题,然后我们跑一下mvn validate看会报什么错误。
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>validation</module>
<module>web</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.imooc</groupId>
<artifactId>demoo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demoo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.10</java.version>
<maven.version>3.3.10</maven.version>
<mybatis.version>2.1.2</mybatis.version>
<enforcer.version>1.4.1</enforcer.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--引入JSR303校验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${enforcer.version}</version>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>display-info</goal>
<goal>enforce</goal>
</goals>
<phase>validate</phase>
<configuration>
<rules>
<!--Rule #1:检验maven版本-->
<requireMavenVersion>
<message>
<![CDATA[This application requires at least Maven with version ${maven.version}.]]>
</message>
<version>[${maven.version},)</version>
</requireMavenVersion>
<!--Rule #2:校验Java版本-->
<requireJavaVersion>
<message>
<![CDATA[This application requires at least JDK ${java.version}.]]>
</message>
<version>[${java.version}.0,)</version>
</requireJavaVersion>
<!--Rule #3:校验投产的版本不能是snapshot-->
<requireReleaseVersion>
<message>Snapshots version is prohibited.</message>
</requireReleaseVersion>
<!--Rule #4:校验pom文件中有没有重复的依赖(相同的GAV)-->
<banDuplicatePomDependencyVersions/>
<!--Rule #5:校验依赖冲突,如果冲突了会报错,然后在<excludes>进行排除管理即可-->
<bannedDependencies>
<!--校验传递性依赖(间接依赖)-->
<searchTransitive>true</searchTransitive>
<excludes/>
</bannedDependencies>
<requireProperty>
<property>project.version</property>
<message>"Project version must be specified."</message>
<regex>.*(\d|-SNAPSHOT)$</regex>
<regexMessage>"Project version must end in a number or -SNAPSHOT."</regexMessage>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
当我们跑了mvn validate后,请大家对照以上pom文件看以下截图,你可以发现上面的头4个错误基本可以在构建环节直接识别,这样的话就可以在技术上有效的约束工作规范,这样是不是更好的体现“约定优于配置”呢?
当然,具体maven-enforcer-plugin还有更多的校验规则,或者你也可以基于它的规范开发你特有的校验规则。具体可以参考阿帕奇http://maven.apache.org/enforcer/maven-enforcer-plugin/index.html
四、后话
实际上这个就是我自己构想中的DevOps持续构建流水线上的关于质量关卡的其中一个小环节。诚然,在工程规约这个大命题下面,实际我们还有更多的事情需要做,后面再慢慢摸索,定期更新完善这个DevOps流水线。
版权声明: 本文为 InfoQ 作者【Man】的原创文章。
原文链接:【http://xie.infoq.cn/article/65ba977e48462960e2f760546】。文章转载请联系作者。
评论