我个人对 akka/pekko 这类 Java-Actor 库十分喜爱, 所以在日常当中也会去为这类 Java 方案做推广;
虽然直接调用内部库函数方法就能满足日常使用, 但是作为后续扩展当中直接声明裸写是不符合工程化规范, 后续多人维护麻烦也挺多的.
如果2-3人的时候可能还不太明显, 随便架个 pom.xml 单项目管理也没什么问题, 但业务扩展出来的时候就很麻烦;
这里说下工作当中可能遇到的问题, 以下就是工作当中实际遇到:
1. 项目刚开始立项国内平台, 直接简单引入 pekko+msgpack 搭建服务端协议
2. 客户端调通之后开始编写业务逻辑, 然后开始跑运营流程追加功能业务
3. 底层依赖没有做封装和业务抽离, 所以直接在内部改动些底层功能, 实际上这时候还没问题
4. 海外需要构建个版本低于国内版本, 这是否问题就开始发作, 出现版本底层割裂问题
5. 国内版本在v1.2的时候底层函数改动参数变动, 但海外版本v1.0依赖这个函数而不依赖逻辑改动
(比如抽奖函数两边最开始一致, 但底层函数更新要求传递随机种子 seed 值, 国内版本已经更新而国外版本不需要更新避免干扰到其他用到函数)
------------------------ 从这里开始就是版本管理崩溃的前兆 -------------------
6. 虽然这次靠着直接复制底层功能类, 手动修改函数调用方法处理完成, 但是结果终归是好的, 可以满足业务正常运行
7. 原先网络库采用 websocket 做传输, 现在为了底层性能需求需要改动成 tcp|udp
8. 第三方库引入又对两个版本产生巨大差异, 海外版本可能落后两个大版本, 但是内部业务还是要维持更新
9. 国内v2.0大版本更新了, 但是海外依旧保持v1.2版本, 这时候运营要求把v2.0国内某些功能业务移动海外v1.2
10. 最可怕的事情就发生了, 底层有着大量没有同步更新导致两边版本底层可能完全对不上, 只能人肉比对版本然后修改变动
11. 随着这种差异版本对比越来越多, 后续版本合并越来越困难, 两个版本不断人肉比对修改第三方引用和调用方式差别越来越大
12. 后面再多出个东南亚针对性等版本, 随着版本越来越分裂的情况下, 维护起来的版本差异越来越大
这里演示上面说的, 单一项目集成第三方库在工作当中的演变情况:
/**
* 假设初始化WebSocket应用, 看起来底层业务逻辑一致
* 外部调用 H5AppV12.write(...) 也是正常
*/
class H5AppV12 {
/**
* 初始响应版本
*/
public void write(WebSocket socket, String message);
}
/**
* 开始为了性能采用TCP模式
* 外部调用就出现问题, 所有原本响应功能都要修改 TcpAppV12.write(...)
* 这里虽然有些函数参数没办法匹配的情况, 但修改下调用其实依旧还能保持功能统一
*/
class TcpAppV12 {
/**
* 之后版本采用原生TCPSocket和二进制流处理
*/
public void write(Socket socket, byte[] message);
}
/**
* 海外上架要求WebSocket那时候的版本, 并且还需要把最新业务比如抽奖功能同步一起
* 而抽奖功能其实内部调用的是最新的 TcpAppV12 版本
*/
class GooglePlayH5AppV10 {
public void write(WebSocket socket, String message);
}
// -----------------------------------------------------------
// 至此目前版本就开始加剧分裂, 后面如果 GooglePlayH5App 版本更新可能就需要人肉去比对三个版本业务逻辑来保持一致
另外这个专题除了说明封装库规划, 还有一点就是学习开源社区是怎么做多人开发和 Java 代码规划化处理,
我们考虑采用知名的大数据开源方案: flink 来作为学习对象.
注意:
flink库里面十分庞杂, 我们没必要全部源码都查看而是只关心底层核心就可以(flink-core|flink-rpc)
首先解析下 pom.xml 的 maven 项目依赖, 用于理解下开源社区的 pom 应该怎么编写:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!-- 上面需要声明采用开源社区的那个许可协议, 这里是基于 apache-2.0 -->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- 这里父依赖, 注意不能随便定义 -->
<!-- 基本上只有 apache 项目才会定义该父类依赖, 如果 MIT 之类项目等或者私人项目是无须处理该依赖 -->
<!-- 注: 如果是个人|公司项目可以无须引入该依赖 -->
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
<version>20</version>
</parent>
<!-- 常规的包名定义, 当时需要说明的是 artifactId 的声明 -->
<!-- 注: 如果你采用多项目 maven 集成架构, 父 pom.xml(根pom.xml) 的 artifactId 声明为 '包名-parent' 作为格式 -->
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.flink</groupId>
<artifactId>flink-parent</artifactId>
<version>2.2-SNAPSHOT</version>
<!-- flink的详情信息 -->
<!-- 注: 这里的 name 命名是有规划的, 其他子项目都被命名为 'Flink : Core' 在日志打印的时候会显示归属包名 -->
<name>Flink :</name>
<packaging>pom</packaging><!-- 声明该根节点(flink-parent) 不包含任何编译功能, 仅作为多项目的 pom -->
<url>https://flink.apache.org</url><!-- 项目的官网地址, 私人项目或没有官网可以不定义 -->
<inceptionYear>2014</inceptionYear> <!-- 比较少用的特殊节点, 用于声明项目创建的年份, 以四位的数字定义 -->
<!-- 开源许可, 该项目代表采用 Apache2.0 规范, 如果是私人不打算开源可以省却这部分定义 -->
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
<!-- 注: 如果采用 GNU 则是修改成以下内容 -->
<license>
<name>GNU General Public License v3.0</name>
<url>https://www.gnu.org/licenses/gpl-3.0.html</url>
<distribution>repo</distribution>
</license>
<!-- 注: MIT则比较特别一点, 首先需要去 https://opensource.org/licenses/MIT 生成 LICENSE 许可文件放在根目录下 -->
<license>
<name>The MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- 暴露给IDE的源代码版本托管信息 -->
<scm>
<url>https://github.com/apache/flink</url> <!-- 源代码管理地址 -->
<connection>[email protected]:apache/flink.git</connection> <!-- 源代码公共管理仓库 -->
<!-- 对于开发者的源代码管理仓库 -->
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/flink.git</developerConnection>
<!-- 注: 如果项目采用 svn 的话这里的仓库地址定义是不一样, 比如下面这样的例子 -->
<!-- <connection>scm:svn:https://github.com/apache/flink</connection> -->
<!-- <developerConnection>scm:svn:https://github.com/apache/flink</developerConnection> -->
</scm>
<!-- 远程项目依赖, 也就是第三方包会优先从这些第三方获取依赖项 -->
<!-- 注: 因为中国特殊的网络原因, 有时候依赖项是很难下载所以私人项目最好配置阿里巴巴|腾讯|华为等远程仓库 -->
<repositories>
<!-- Add Redhat GA repository for jackson-mapper-asl -->
<repository>
<id>redhat</id>
<url>https://maven.repository.redhat.com/ga/</url>
</repository>
<repository>
<id>repository.jboss.org</id>
<url>https://repository.jboss.org/nexus/content/groups/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<!-- POM子项目依赖 -->
<modules>
<!-- 这里的子库省略等后续展开说明 -->
</modules>
<!-- 全局的 Maven 属性定义 -->
<!-- 注:对于全局属性和版本锁定必须在该配置之中定义, 这里我会选几个比较典型的配置节点说明 -->
<properties>
<!-- 比较常规的字符集声明 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Java平台版本声明 -->
<!-- 注: 如果从头开发采用比较新的版本需要注意该项 -->
<source.java.version>11</source.java.version><!-- 编译选择的版本 -->
<target.java.version>17</target.java.version><!-- 运行生成的版本 -->
<!-- 下面这个声明其实是针对IDEA这个IDE工具, 用来覆盖掉最开始 apache-parent 上级版本 maven 兼容性 -->
<!-- Overwrite default values from parent pom.
IntelliJ IDEA is (sometimes?) using those values to choose target language level
and thus is changing back to java 1.6 on each maven re-import -->
<maven.compiler.source>${target.java.version}</maven.compiler.source>
<maven.compiler.target>${target.java.version}</maven.compiler.target>
<!-- 这里是有趣的自定义属性配置技巧, 用于触发 maven-shade-plugin 的执行从而生成动态 POM 文件 -->
<!-- 注: 很有用技巧, Maven 默认的 install 策略是直接复制工程的 pom.xml, 不会解析其中的 properties -->
<!-- 注: 这也就导致所有打包出来 pom.xml 内部 properties 属性值一致, 当时正常不同 profile 打包出来不止有 prod(正式包) 还有 dev(开发包) -->
<!-- 注: 所以为了打包过程之中能够把 properties 属性值全部替换成运行时的值, 才需要这个配置 -->
<!-- 注: shaded 就是代表了这是要被动态打包 POM 覆盖的 properties 属性 -->
<!-- 注: 比较庞大的项目才需要这种编写插件的行为, 一般简单插件可以不引入该特性, 因为需要编写大量插件逻辑可能会导致开发周期变长 -->
<flink.shaded.version>20.0</flink.shaded.version>
<flink.shaded.jackson.version>2.18.2</flink.shaded.jackson.version>
<flink.shaded.jsonpath.version>2.9.0</flink.shaded.jsonpath.version>
<!-- 设置全局的第三方库时候的 <optional></optional> 属性节点 -->
<flink.markBundledAsOptional>true</flink.markBundledAsOptional>
<!-- 终端启动的最大堆进程内存大小 -->
<flink.XmxMax>3072m</flink.XmxMax>
<!-- flink测试样例和单元测试时候最大堆内存大小 -->
<flink.XmxITCase>1536m</flink.XmxITCase>
<flink.XmxUnitTest>768m</flink.XmxUnitTest>
<!-- 注: 这是正确的操作, 如果设备内存不够, 程序会将你内存吃满, 有效做好内存预分配方便程序不会爆内存 -->
<!-- 引入 scala 方便支持 actor 组件 -->
<!-- 注: 最新版本 scala 变动极大, 所以这里的版本需要参照最新版本 scala -->
<scala.macros.version>2.1.1</scala.macros.version>
<scala.version>2.12.20</scala.version>
<scala.binary.version>2.12</scala.binary.version>
<!-- 引入测试单元框架 -->
<!-- 注: 这里之所以采用两个版本引入就是最大程度兼容库之间差别, 第三方库可能有的不再更新单元测试停留在 junit4 之中 -->
<junit4.version>4.13.2</junit4.version>
<junit5.version>5.11.4</junit5.version>
<!-- 代码开发功能, 这里就是多人开发多人风格统一的保证; 这里我会着重声明, 保持自己的代码正规化能够纠正很多毛病 -->
<!-- 注: 官方内部版本可能比较老, 获取最新版本: https://github.com/diffplug/spotless 和 https://github.com/checkstyle/checkstyle -->
<!-- 注: 如果你的项目打算参与多人开发的话, 这个插件推荐配置才能保证所有人代码风格一致 -->
<!-- maven-checkstyle-plugin 内部 com.puppycrawl.tools 代码插件版本 -->
<!-- 注: 这里之所以要单独另外声明版本就是因为 maven-checkstyle-plugin 和 checkstyle 高版本有冲突, 所以需要锁定在此版本防止两者异常 -->
<checkstyle.version>10.18.2</checkstyle.version>
<!-- Spotless 插件确认是否编译的属性值, 默认 false 代表不做代码检查 -->
<!-- 注: 通过在追加 -Dspotless.skip=true 可以在 pipeline 打包工程自动化打包(CI)验证, 防止非法不合规代码打包-->
<spotless.skip>false</spotless.skip>
<spotless.version>2.43.0</spotless.version>
<!-- 追加Scala代码验证功能, 默认有时候可能会用到 Scala 混合编程, 所以也需要追加下代码风格验证 -->
<spotless.scalafmt.version>3.4.3</spotless.scalafmt.version>
<!-- 规范包声明引入的位置与空行分割, 具体见 spotless-maven-plugin 常见配置 -->
<spotless.delimiter>package</spotless.delimiter>
<!-- 对于 spotless 开源许可需要再次声明 -->
<!-- 注: Apache-2.0 规定了任何被分发的文件必须在显著位置包含版权声明和许可声明, 所以任何用到了相关第三方库都需要在显著地方声明开源许可 -->
<spotless.license.header>
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
</spotless.license.header>
<!-- 这里需要说下可能会用到更高级自动化模块化单元测试, flink 项目庞大且依赖复杂, 底层修改变动可能会直接影响到所有依赖 -->
<!-- 其实这不是必须, 如果不是像 flink 一样架构庞大的话, 引入这个自动化单元测试反而会耗费大量时间在无用功上 -->
<!-- 自动化测试命令行的启动配置 -->
<flink.surefire.baseArgLine>-XX:+UseG1GC -Xms256m -XX:+IgnoreUnrecognizedVMOptions ${surefire.module.config}
</flink.surefire.baseArgLine>
<!-- 参与自动化测试的所有模块对象 -->
<!-- This property should contain the add-opens/add-exports commands required for the tests
in the given module to pass.
It MUST be a space-separated list not containing any newlines,
of entries in the form '[-]{2}add-[opens|exports]=<module>/<package>=ALL-UNNAMED'.-->
<surefire.module.config/>
<!-- surefire 单元测试的对应排除说明 -->
<surefire.excludedGroups.github-actions/>
<surefire.excludedGroups.adaptive-scheduler/>
<surefire.excludedGroups.jdk/>
<!-- surefire 单元测试的对应测试文件单元 -->
<!-- Can be set to any value to reproduce a specific build. -->
<test.randomization.seed/>
<test.unit.pattern>**/*Test.*</test.unit.pattern>
<!-- 其他略 -->
</properties>
<!-- 第三方依赖库 -->
<dependencies>
<!-- flink 的小技巧, 通过重写写插件功能让 flink-shaded-force-shading 命令触发从而 properties 属性值覆盖 -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-force-shading</artifactId>
<optional>${flink.markBundledAsOptional}</optional>
</dependency>
<!-- 所有项目的共同依赖项 -->
<!-- 注:这里有的功能库可以考虑使用, 有些功能确实能够节约开发时间 -->
<!-- Logging 基础 API, 推荐引入 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- 'javax.annotation' classes like '@Nullable' -->
<!-- 基于 JSR305 提案的静态分析库, 用于防止空指针|资源泄漏等问题, 至此 '@Nullable' 等声明检查 -->
<!-- Java8 之后已经在 java.lang 包原生集成 JSR305 至此, 如果项目新立项 Java8 以上可以不需要引入该依赖 -->
<!-- 注: 新立项的项目不需要该依赖, 可以直接抛弃直接采用内置 java.lang 包使用 -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<!-- 以下是单元测试相关包 -->
<!-- 注: JUint的核心模块 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- 注: JUint的测试调度模块, 用来区分 JUint4|JUint5 兼容性 -->
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- 注: 高级的断言库, 支持复杂链式调用: https://github.com/assertj/assertj -->
<!-- 注: 看情况来引入, 比 JUint 支持更加复杂的测试断言且自然, 看个人喜好(我一般为了简洁会尽可能减少引入) -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!-- 注: mockito 其实就是模拟数据功能, 所以这里跳过就不多说明 , 按照个人需求来引入即可 -->
<!-- 把测试单元设置默认使用 log4j 日志框架 -->
<!-- 把 slf4j 日志连接到 log4j 实现, scope 则是声明限定为 test 测试框架之中 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<!-- log4j 核心框架接口实现, 提供基础的抽象通用功能接口实现, scope 则是声明限定为 test 测试框架之中 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>test</scope>
</dependency>
<!-- log4j 核心的基础模块, scope 则是声明限定为 test 测试框架之中 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<!-- 注: 之所以要引入 log4j-api 之后再次引入 log4j-1.2-api, 是因为两者接口是不兼容的, 需要做好兼容 -->
<!-- 注: 如果确定版本不再兼容 log4j-1 版本, 是可以不需要引入该依赖 -->
<dependency>
<!-- API bridge between log4j 1 and 2 -->
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 第三方的包版本控制, 用来定义锁定包版本 -->
<dependencyManagement>
<!-- WARN:
DO NOT put guava,
protobuf,
asm,
netty
here. It will overwrite Hadoop's guava dependency (even though we handle it
separatly in the flink-shaded-hadoop-2 dependency).
-->
<!-- 以上注释讲版本控制不要放置 guava, protobuf, asm, netty 相关库, 会覆盖掉其他库内部版本 -->
<dependencies>
<!-- 以下就是采用 flink-shaded-force-shading 的技巧, 用于插件后续调用来覆写配置 -->
<!-- 注: 需要了解 maven-shade-plugin 来编写扩展功能, 上手配置其实也比较复杂, 可以了解 https://maven.apache.org/plugins/maven-shade-plugin/ -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-force-shading</artifactId>
<version>${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-asm-9</artifactId>
<version>9.6-${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-guava</artifactId>
<version>33.4.0-jre-${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-jackson</artifactId>
<version>${flink.shaded.jackson.version}-${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-jackson-module-jsonSchema</artifactId>
<version>${flink.shaded.jackson.version}-${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-netty</artifactId>
<version>4.1.100.Final-${flink.shaded.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-shaded-netty-tcnative-dynamic</artifactId>
<version>2.0.62.Final-${flink.shaded.version}</version>
<scope>test</scope>
</dependency>
<!-- 注: 以下功能不做过多说明, 其实就读取 properties 内部属性值锁定版本 -->
<!-- This manages the 'javax.annotation' annotations (JSR305) -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>1.3.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-layout-template-json</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<!-- API bridge between log4j 1 and 2 -->
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- For dependency convergence -->
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit5.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit4.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>${scala.version}</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_${scala.binary.version}</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
<!-- 注: 这里为了节省说明, 因为本身 flink 涉及庞大依赖所以节约下时间说明后续 -->
<!-- 注: 但是必须要记住, 无论再怎么引入都必须要在开发的是否对版本做好锁定! -->
</dependencies>
</dependencyManagement>
<!-- 项目环境配置, 根据不同的环境或需求定制项目的构建行为 -->
<profiles>
<!-- 这里就是针对 intellij 打包自动配置将 Optional 全部设置为 false -->
<profile>
<id>intellij</id>
<activation>
<property>
<name>idea.version</name>
</property>
</activation>
<properties>
<!-- Set to false so that all required dependencies are put on the classpath,
since IntelliJ does not work against jars produced by the shade plugin
(which may bundled said classes). -->
<flink.markBundledAsOptional>false</flink.markBundledAsOptional>
</properties>
</profile>
<!-- 小技巧: 按照 Java17 来打包并且重写内部配置 -->
<profile>
<id>java17</id>
<activation>
<jdk>[17,)</jdk>
</activation>
<properties>
<surefire.excludedGroups.jdk>org.apache.flink.testutils.junit.FailsOnJava17
</surefire.excludedGroups.jdk>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludedGroups>
${surefire.excludedGroups.github-actions},
${surefire.excludedGroups.adaptive-scheduler},
${surefire.excludedGroups.jdk},
</excludedGroups>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<!-- 这里实际上在 IDEA 确认 profile 输入对应 id 就可以手动切换打包运行功能 -->
<!-- 注: 这里主要开发过程的是否声明打包的配置, 多人开发的就是要求强制让所有人都依赖对应某个配置来打包 -->
</profiles>
<!-- 打包和打包插件配置 -->
<!-- 这里建议查看下 flink 官方并理解, 因为编写打包插件本身就是需要单独去学习, 所以这里跳过这方面说明 -->
<!-- 注: 这里只说明代码风格统一和基础功能打包, 其他最好自己查询功能来学习 -->
<build>
<!-- 插件引入 -->
<plugins>
<!-- 代码风格统一插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
</plugin>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<!-- 其他自行参照官方说明 -->
</plugins>
<!-- 插件库版本锁定 -->
<!-- 注: 这里也只节选一些库来讲解 -->
<pluginManagement>
<plugins>
<!-- maven 打包插件, 具体版本可以看 https://maven.apache.org/plugins/maven-compiler-plugin/ 文档说明 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<!-- Make sure that we only use Java 11 compatible APIs -->
<!-- 兼容 Java11 的配置, 后续需要声明该配置项 -->
<source>${source.java.version}</source>
<target>${target.java.version}</target>
<!-- The semantics of this option are reversed, see MCOMPILER-209. -->
<!-- 是否启动增量编译(false或者不配置默认就是禁用), 虽然能够减少编译时间, 但是有时候莫名其妙会导致编译少了东西 -->
<useIncrementalCompilation>false</useIncrementalCompilation>
<compilerArgs>
<!-- Prevents recompilation due to missing package-info.class, see MCOMPILER-205 -->
<!-- 避免因缺少 package-info.class 文件而导致重新编译 -->
<arg>-Xpkginfo:always</arg>
<!-- 用来避免Java9以上的反射模块在调用内部包是否的权限问题 -->
<!-- JDK9(java.management|java.rmi 等)默认对内部包(以 sun. 或 com.sun. 开头)进行封装, 外部代码无法通过反射、类加载等方式访问, 否则会抛出权限异常 -->
<!-- 注: 许多第三方库|框架|旧代码等 hook 监控工具依赖于 JDK 内部 API, 如果没有加入这种配置可能会导致权限不足报错 -->
<arg>--add-exports=java.management/sun.management=ALL-UNNAMED</arg>
<arg>--add-exports=java.rmi/sun.rmi.registry=ALL-UNNAMED</arg>
<arg>--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- 强制实施项目构建规则的插件, 主要作用是确保项目构建过程做代码规范合法性检查 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- 代码风格统一检查插件 -->
<!-- 注: 具体的文档可见 https://maven.apache.org/plugins/maven-checkstyle-plugin/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.3.1</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<!-- Note: match version with docs/flinkDev/ide_setup.md -->
<version>${checkstyle.version}</version>
</dependency>
</dependencies>
<!-- 当调用到 validate 指令就直接会进行代码检查 -->
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- 注: 下面就是代码合法性规则文件 -->
<!-- suppressionsLocation: 代码忽略规则文件 -->
<!-- includeTestSourceDirectory: 是否要对项目 tests 的测试单元一起做检查 -->
<!-- configLocation:代码风格规则主文件 -->
<!-- logViolationsToConsole:是否代码风格检查结果输出到命令行窗口 -->
<!-- failOnViolation: 当代码风格非法的时候时候要直接停止构建 -->
<suppressionsLocation>/tools/maven/suppressions.xml</suppressionsLocation>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<configLocation>/tools/maven/checkstyle.xml</configLocation>
<logViolationsToConsole>true</logViolationsToConsole>
<failOnViolation>true</failOnViolation>
</configuration>
</plugin>
<!-- 代码风格检查插件 -->
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless.version}</version>
<configuration>
<java>
<!-- Google 代码风格检查, 具体可以见 https://google.github.io/styleguide/javaguide.html -->
<googleJavaFormat>
<version>1.24.0</version>
<style>AOSP</style>
</googleJavaFormat>
<!-- \# refers to the static imports -->
<!-- 静态引入之后的检查包 -->
<importOrder>
<order>org.apache.flink,org.apache.flink.shaded,,javax,java,scala,\#</order>
</importOrder>
<removeUnusedImports/>
</java>
</configuration>
<executions>
<execution>
<id>spotless-check</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 其他略, 可以参考官方文档来学习 -->
</plugins>
</pluginManagement>
</build>
</project>
flink 的根 POM 配置里面其实涵盖了大量一般常规我们用不到的地方, 需要我们自己去鉴别所需的组件功能;
但是可以从中学到不少东西, 去了解一个开源项目应该去怎么统筹和规划处理.
Apache2.0 这种其实更像是君子协议, 引用之后闭源处理其实也没办法, 其实大部分私人项目构建前期都不需要这么插件
这里需要说明下怎么去学习开源社区的项目代码, 首先就像上面看的 POM 规范之中, 应该要学习命名的规范和版本锁定概念,
而比较次要的是 build 的打包功能学习方便直接结合打包平台自动化打包.
刚接触一定要很清楚主要和次要差别, 你是来学习功能设计和架构规划, 不是来学习插件配置打包