开发工具

升级 Maven 插件

升级 Maven 插件

D瓜哥
D瓜哥在 关于升级 Spring 等依赖的一些经验 中,介绍了一些升级 Spring 等依赖的一些经验。在 升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 的影响 中,分析了升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 异常的影响。在升级中,还遇到一些 Maven 插件相关的问题。这里也分享出来,希望对大家有所帮助。 Properties 文件编码错误 在升级过程中,遇到过 Properties 文件编码错误的问题。可以通过配置对应的编码来解决这个问题。配置如下: <!-- D瓜哥 · https://www.diguage.com --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.3.0</version> <configuration> <propertiesEncoding>ISO-8859-1</propertiesEncoding> </configuration> </plugin> 参考资料 Apache Maven Resources Plugin – Filtering Properties Files。 使用 Maven Enforcer 插件检查依赖 私以为“机器可以干的事情,就应该交给机器干”。对于依赖管理,Maven Enforcer 插件就可以对依赖做必要的检查。所以,推荐使用 Maven Enforcer 插件来检查低版本及有安全漏洞的依赖。 详细介绍请参考: 使用 Maven Enforcer 插件检查依赖 字节码文件包含原始参数名称 一些对外发布的依赖,建议将原始参数名称编译到构建结果里。可以通过指定构建参数来完成。 <!-- D瓜哥 · https://www.diguage.com --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <!-- https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html --> <compilerArgs> <arg>-parameters</arg> </compilerArgs> <parameters>true</parameters> </configuration> </plugin> 参考资料 Apache Maven Compiler Plugin – Pass Compiler Arguments 解决测试依赖问题 部分项目可能已经使用了 JUnit 5,但是执行测试代码时,可能报错。可以使用如下配置来解决这个问题:
升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 的影响

升级 iBATIS/MyBATIS 对处理 DuplicateKeyException 的影响

D瓜哥
在 关于升级 Spring 等依赖的一些经验 中,分享了一些开源依赖的升级经验。部分小伙伴质疑升级 iBATIS/MyBATIS 会影响对 DuplicateKeyException 异常的处理。这篇文章就从源码分析/代码更新的就角度来分析一下升级相关依赖是否会对 DuplicateKeyException 异常的处理带来实质性的影响。 由于主要的技术栈涉及 MySQL 驱动、iBATIS、MyBATIS、Spring 周边等。所以,本文仅分析涉及的这些依赖。 D瓜哥使用 MySQL: Employees Sample Database 搭建了一个 Spring + MyBATIS + MySQL Connector/J 的测试环境。连续插入两条一样的数据,单步调试,在 com.mysql.jdbc.MysqlIO#sendCommand 方法中,就可以观察到如下异常: 图 1. MySQL Error 1062 从这里可以明显看出,MySQL 驱动返回的异常中, venderCode 编码是 1062。 顺着这个线,往上走,到 org.apache.ibatis.session.defaults.DefaultSqlSession#update(java.lang.String, java.lang.Object) 方法中,可以看到, 图 2. MyBATIS wrap Exception 在这里,会将 SQLException 包装成 PersistenceException,这也是 MyBATIS 对外暴露的统一的异常类。 继续往上走,就到了 org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke 方法: 图 3. MyBATIS translateException 在 SqlSessionInterceptor#invoke 方法的异常处理中,将 PersistenceException 异常通过 org.springframework.dao.support.PersistenceExceptionTranslator#translateExceptionIfPossible 方法,将异常转换成 DataAccessException 对象。 DataAccessException 类是 Spring 数据访问的异常类基类。
关于升级 Spring 等依赖的一些经验

关于升级 Spring 等依赖的一些经验

D瓜哥
到公司后,熟悉了一些项目后,发现大部分项目的依赖都比较陈旧,比如某些项目还在使用 Spring 3.x 的版本。所以,在进行需求开发时,也顺手把一些项目的依赖给升级了一下。周五,一个小伙伴问我关于升级 Spring 的经验。正好趁此机会,把一些经验总结一下。 下面的描述以 Java 8 为准,没有在其他版本 Java 上试验过。参考时,请慎重。描述的原则如下: 尽量选择还在维护中的版本,而不是已经 End of Life 的过时版。这样有问题可以及时反馈并得到修复。 Java 8 是目标版本,所以,一定要兼容 Java 8。 Spring Framework 升级 Spring Framework 从 3.2.6.RELEASE 开始提供 BOM。可以利用 BOM 简化 Spring 依赖声明: <!-- D瓜哥 · https://www.diguage.com --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>5.3.25</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 这样,就不需要重复声明 Spring 依赖的版本,直接使用即可。 Spring Framework Bom 保证了 Spring 自身依赖的版本统一。 这里,关于 Spring 的升级,还有几点需要说明: 从 Spring 3.X 升级到 Spring 4.X+ 后,原来的 MappingJacksonHttpMessageConverter 已经被删除了;直接使用 MappingJackson2HttpMessageConverter 即可。 从 Spring 3.0.0.RELEASE 到 Spring 3.1.4.RELEASE,Spring 有一个 spring-asm,如果不再使用这个区间的 Spring,请把这个依赖删掉。 如果使用了 Apache Velocity 1.X 作为前端模板,由于 Spring 5+ 将相关集成代码删除,所以,只能将 Spring 升级到 4.3.30.RELEASE。相关 BOM 如下: <!-- D瓜哥 · https://www.diguage.com --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-framework-bom</artifactId> <version>4.3.30.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
使用 Maven Enforcer 插件检查依赖

使用 Maven Enforcer 插件检查依赖

D瓜哥
最近公司项目要对一些内部依赖做集中升级。为此,D瓜哥发布了一个 BOM(BOM stands for Bill Of Materials),用于规范项目依赖及版本。 但是升级后,效果不理想,检查发现还是有不少依赖的版本依然不符合要求。经同事提醒,可以使用 Apache Maven Enforcer 来做规范检查,测试一下效果确实不错。 将 Apache Maven Enforcer 和 Extra Enforcer Rules 的文档大致巴拉了一遍之后,根据项目的实际情况,挑选出来可用规则如下: 比较有用的几个规则 bannedDependencies – 排除不需要的依赖,引入需要的依赖。 banDuplicatePomDependencyVersions – 防止依赖重复声明。 dependencyConvergence – 确保所有依赖收敛到相同的版本。也可以考虑加入。 reactorModuleConvergence – 多模块开发时,确保父子模块的版本是一致的。 requireJavaVersion – 检查 JDK 的版本 requireMavenVersion – 检查 Maven 的版本 requireReleaseVersion – 这个可以通过激活生产环境的 profile 来启用该规则,保证发布的不是快照版。 requireUpperBoundDeps – 确保直接引用的依赖不比间接解析出来的依赖版本低。感觉这个也挺有用,但是使用方式还没搞清楚。实例有些模糊。 banDuplicateClasses – 检查重复类定义。可以避免一些特殊情况。 requirePropertyDiverges – 确保项目定义的属性与依赖中包含的属性不重复。 enforceBytecodeVersion – 确保使用的字节码版本不高于指定版本。 banCircularDependencies – 确保没有循环依赖。 requireEncoding – 指定项目字符集。 实践总结 D瓜哥把上面的规则几乎全部试用了一遍,把发现的一些需要特别注意的地方标注记录一下吧: banDuplicateClasses — 这个插件还是很棒的。使用的时候,成功检查出废弃不用的依赖(废弃依赖被收入到另外一个依赖中了。)。不过,也发现一些问题,项目中使用了 netty-all 及 Netty 的其他模块依赖。但是,并没有检查出来,感觉是项目代码有直接依赖的重复类才会被检测出来。 requireUpperBoundDeps — 开启这个检查时,发现间接引用了 commons-lang:commons-lang:2.6,但是项目直接声明的依赖是 commons-lang:commons-lang:2.5,就直接报错了。私以为这个检查规则还是很赞的。但是,因为我们的项目中有有依赖 Gson 1.X,也有 Gson 2.X 的,而且这两个版本在处理父子类有相同字段时的存在抛异常的差异,所以无法启用,实在可惜。 reactorModuleConvergence –- 多模块开发时,确保父子模块的版本是一致的。这个规则还是很赞的。但是,因为我测试的模块不存在这个问题,所以,没有触发报警。 requirePropertyDiverges — 本想启用这个规则,看了一下配置,着实麻烦,而且不是全局检查,似乎是检查指定配置项,感觉不是很满意。没有启用。 enforceBytecodeVersion — 检查字节码版本。这个是不超过上限,我是想检查下限,所以没有启用。反思:在写这个文章时,又思考了一下,检查下限是有问题的,一些陈旧的依赖就不能使用了。但是这些依赖是没有问题的。 banCircularDependencies — 这个规则似乎 Maven 已经内置了,以前遇到过这样的场景,Maven 直接报错了。所以,就没有启用这个规则。 requireEncoding — 这个规则非常棒。在试用过程中发现,它会把存 ASCII 字符的 UTF-8 文件判定为 US-ASCII 编码。没有找到好的办法来解决这个问题。所以,可惜没有启用。
文档技术方案选型:AsciiDoc vs Markdown

文档技术方案选型:AsciiDoc vs Markdown

D瓜哥在前面的文章 使用 Hugo 搭建博客 中介绍了如何用 Hugo 搭建个人博客。部门准备系统地整理一下各个小组的文档。恰好 D瓜哥 对写文档非常感兴趣,正好写个材料分享一下血泪经验。 编辑进化之路 第一代:WordPress 缺点:写作和排版割裂,排版耗时且繁琐 第二代:MarkDown 缺点:方言众多,工具链不够完整。 现在已经改观很多。 第三代:AsciiDoc 轻量级标记语言的优点 思路与格式融为一体 在整理文档时,随手加入格式管理,不需要为格式分心,也无须浪费时间调整排版。 代码高亮 AsciiDoc 与 MarkDown 都支持 /** * @author D瓜哥 · https://www.diguage.com/ */ public class Main { public static void main(String[] args) { System.out.println("Hello, D瓜哥!"); } } 文本格式 文本格式,天然跨平台,支持性好,方便编辑与管理。 结合 Git,支持版本管理。 生态完善 Markdown Hugo: The world’s fastest framework for building websites — Hugo 使用 yuin/goldmark: A markdown parser written in Go. 来做转换工作。也支持 AsciiDoc,不过需要挑选比较合适的主题: Hugo Themes。 AsciiDoc Antora — The multi-repository documentation site generator for tech writers who writing in AsciiDoc. Asciidoctor Diagram — 支持多种文本画图工具。 Asciidoctor EPUB3 Documentation — 可以直接将 AsciiDoc 文档转化成 EPUB 电子书。 Asciidoctor PDF — 可以直接将 AsciiDoc 文档转化成 PDF 文档。 常见插件的支持:Maven、IntelliJ IDEA、VS Code 等。
优化网站

优化网站

D瓜哥
前几年应大势所趋,使用 Let’s Encrypt 给所有网站都上了 HTTPS。因为去年年中把博客托管到 GitHub 上了,导致一起申请 HTTPS 证书的站点无法按时更新证书。所以,所有证书都过期了。前几天有朋友发消息问我,Byte Buddy 的中文文档是不是我搞的?正好借机把证书更新了一下。 此后不久,无意间查看了一下网站服务器的操作系统和 Nginx 版本,发现竟然是 Ubuntu 16.04 + Nginx 1.12。Ubuntu 16.04 都”过期“了,正好得空升级一下。 升级操作系统 以前没有升级过操作系统大版本,正好借此机会练手: # 升级操作系统版本执行,先做一下常规升级 sudo apt-get update sudo apt-get upgrade sudo reboot # 检查可以升级的版本 sudo do-release-upgrade -c # 开始升级 sudo do-release-upgrade 升级完成后,检查操作系统版本: $ cat /etc/os-release NAME="Ubuntu" VERSION="20.04.3 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.3 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=focal UBUNTU_CODENAME=focal 有几点需要注意: LTS 版本升级,只能一步一步升级,从 16.04 升级到 18.04,再从 18.04 升级到 20.04。不能跳级。 升级过程不能中断,需要逐步确认。 如果升级中断,系统就会处在一个中间阶段,不能升级,不能重启(我遇到的情况)。需要人工介入处理,继续升级完成才行: sudo dpkg --configure -a # 执行上述命令失败是,删除两个锁文件,再次执行即可 sudo rm -rf /var/lib/dpkg/lock sudo rm /var/lib/dpkg/lock-frontend sudo dpkg --configure -a sudo apt-get update sudo apt-get dist-upgrade sudo do-release-upgrade sudo reboot
日志最佳实践探究

日志最佳实践探究

加入公司以来,参与了很多个项目的开发维护;也排查处理过很多线上问题;为了写 Mock 测试,也专门去日志系统上扒拉过不少日志等等。在整个过程中,对日志的认识有了不少更深刻的认识和体会。也发现不少问题。这里先从存在的问题展开论述。 日志存在的问题 从个人的眼光上来看,当前的系统存在如下问题: 必要日志没有打印出来,导致在追踪问题或测试代码时,带来不必要的麻烦。比如查看一个接口的返回值用于 Mock 测试;再比如 RPC 调用报错,返回值以及错误信息没有打印到日志中,不知道具体错误原因是什么。 日志抽取中日志路径配置错误,导致日志重复收集,带来不必要的处理和存储成本。 日志代码不规范,导致不必要的性能消耗;或者大促时,日志降级不生效。 日志框架繁多,造成造成冲突,遗漏部分日志。 日志配置不规范,不利于日志的采集和清洗。 日志和调用链路物理隔离,查看一个请求的整个调用链路上的日志非常不方便,不利于问题的快速排查和定位。 大家的系统中,存在什么样的日志问题?欢迎留言交流讨论。 针对这些问题,我觉得有些地方值得发力一下。然后,做了一些探索,总结一下,以备后续使用。 日志最佳实践探索 对于日志的使用,相信所有的开发人员都比较清楚,网上也有大量资料,相关日志框架的官方文档,也写的非常详尽,这里就不再赘述。 本文从一个角度对日志规范进行探究:在排查问题时,能否通过日志来尽快地了解系统运行状态,定位问题原因?另外,由于 Java 的日志框架特别多,有一些比较容易迷惑的问题,尝试做出一点总结。 系统运行后,不严格地说,再去观察系统运行状态,就类似于在黑夜中行走。此时,向你扔过来一块板砖🧱,那么,事后如何追责呢? 请问:你能否成功躲开这块叫做 Bug 的板砖🧱? 日志用来记录用户操作、系统运行状态等,是一个系统的重要组成部分。然而,由于日志通常不属于系统的核心功能,但是在日志对于排查问题,有无可替代的作用,理应得到所有开发人员的重视(不重视,怎么甩锅?!)! If dog is a man’s best friend, logs are software engineer’s best friend. — Geshan Manandhar Logging best practices 好的日志可以帮助系统的开发和运维人员: 了解线上系统的运行状态 快速准确定位线上问题 发现系统瓶颈 预警系统潜在风险 挖掘产品最大价值 可以将一个流程完整串起来(比如orderId) …… 不好的日志导致: 对系统的运行状态一知半解,甚至一无所知 系统出现问题无法定位,或者需要花费巨大的时间和精力 无法发现系统瓶颈,不知优化从何做起 无法基于日志对系统运行过程中的错误和潜在风险进行监控和报警 对挖掘用户行为和提升产品价值毫无帮助 ……
AWK 简介

AWK 简介

这周需要处理一个日志文件,有一次体会到 AWK 强大和方便,但也认识到自己对 AWK 了解的粗浅。所以,写篇文章再深入学习一下。 根据维基百科显示,AWK 于二十世纪七十年代在 Bell Labs 创建;其名字来源于三位创始人: Alfred Aho、Peter Weinberger and Brian Kernighan。AWK 是一个现在几乎每台 Linux 机器上都会有这个命令。 AWK 是一种领域专用语言,专用设计用于文本处理,常用于提取文本或者生成报告。 AWK 也像 Shell 一样,方言和实现众多。D瓜哥这里选择最常用的 GNU AWK 实现。 AWK 是以行为单位来处理文本的。它不仅仅是一个命令行,而且是一门语言。 先展示一下我们的实例程序: $ cat employee.txt ajay manager account 45000 sunil clerk account 25000 varun manager sales 50000 amit manager account 47000 tarun peon sales 15000 deepak clerk sales 23000 sunil peon sales 13000 satvik director purchase 80000 AWK 的基本用法如下: # ① 基本格式 $ awk 动作 文件名 # ② 标准 I/O 格式 $ cat 文件名 | awk 动作
使用 Hugo 搭建博客

使用 Hugo 搭建博客

D瓜哥
一个朋友对D瓜哥的博客感兴趣,觉得很好玩。问我怎么玩,D瓜哥也懒得手把手教了,干脆写篇文章来做个说明吧。也许对其他朋友也有所帮助。 潮起潮落 D瓜哥早在 2012年就使用 WordPress 搭建了一个博客: "地瓜哥"博客网—分享技术带来的喜悦,WordPress 不亏是全世界最流行的开源 CMS 系统,各种插件可以满足非常对的需求。当年D瓜哥还想研究一下它的源代码,可惜对 PHP(对,就是那个拍黄片的)无感,没有坚持下去。 但是,在熟悉了 MarkDown、 Asciidoctor(D瓜哥是 AsciiDoctor 的死忠粉,坚决支持它的发展) 等轻量级标记语言后,愈发觉得 WordPress 太繁琐:写作一个小时,排版发布一小时。实在是太浪费时间了。 先尝试了一下 Antora,之所以选它,是因为它是 AsciiDoctor 的作者发起的项目,对 AsciiDoctor 的支持性非常好。尝试了一段时间后,发现它更适合写产品说明书,更适合像阿里云等这种对外提供产品,需要提供在线产品说明书的情况。不适合做个人博客。 去年,经过多次测试后(主要测试对 AsciiDoctor 的支持性),发现现在D瓜哥用的这个主题对 AsciiDoctor 支持得不错,随后下定决心切换到了 Hugo。 Hugo 简介 关于 Hugo 的介绍,直接转摘维基百科的介绍了: Hugo 是一个用 Go 编写的静态网站生成器,2013由 Steve Francia 原创,自 v0.14 (2015年) 由 Bjørn Erik Pedersen 主力开发,并由全球各地的开发者和用户提交贡献。Hugo 以 Apache License 2.0 许可的开放源代码项目。 Hugo 一般只需几秒钟就能生成一个网站(每页少于 1 毫秒),被称为“世界上最快的网站构建框架”,也使 Hugo 大受欢迎,成为最热门的静态网站生成器之一,被广泛采用。例如,2015年7月,Netlify 推出专为 Hugo 而设的网站托管服务,而2017年,Smashing Magazine 推出重新设计的官方网站,从原来的 WordPress 迁移到基于 Hugo 的 JAMstack 解决方案。 — https://zh.wikipedia.org/wiki/Hugo_(軟件)