虽然maven的目标是使项目构建是可移植的,尽量使在任何机器下都可以构建且结果相同,但是仍然会有一些情况需要我们根据环境等信息来构建不同的内容,这时候就需要用到 maven profiles
DI框架-Guice入门
10分钟入门 Elasticsearch 使用
在当今信息爆炸的时代,对于大规模数据的搜索、分析和可视化变得至关重要。Elasticsearch(ES)作为一款开源搜索和分析引擎,为开发者和企业提供了一种强大而灵活的工具,能够轻松处理海量数据,并提供高效的搜索和分析能力
本文围绕 Elasticsearch 来讲解一下如何创建索引、进行数据写入和查询,快速入门ES使用
协程之Kotlin
一般我们在 Java 项目中做并发编程,基本都是通过创建线程的方式来执行(JDK21支持了虚拟线程),但是线程有如下问题
- 线程是不能无限创建的,而是受到操作系统的限制
- 线程切换的时候有较高的上下文切换的成本
而协程可以理解为轻量级的线程,可以在一个线程中执行多个任务,而不需要线程切换的开销,同时也避免了线程数量的限制
这里看一下kotlin中的协程,首先需要引入单独的依赖包
1 | // gradle.kts |
统一流程下的差异点解决方案-扩展点
我们都知道设计原则,追求开放封闭原则,封装变化
比如我们有一个统一的流程,运转良好且自认为设计的不错,这时来了个需求,说需要针对不同的来源要有一些特殊的处理,这时候我们如何支持呢?
一种简单的解决方案是加一个 if 判断,做一点特殊逻辑,但是这不是一个好的实践
这时候我们想到可以将这部分差异功能抽象为一个接口,然后有一种特殊的实现类还有一个默认的实现类。但是这时候另一个问题出现了,在执行到这部分逻辑的时候,如何确认使用哪个实现类呢(需要一个定位逻辑)
后面可能对于这个来源,还有一个地方需要处理,这时候又要有一套接口和定位逻辑
这时候我们可以考虑一下使用扩展点的方案,我们看下 COLA 提供的扩展点(示例来自源码)
如何用非代理的方式实现java拦截器
《代码精进之路》中看到的拦截器实现,方式比较巧妙,在此记录一下
一般我们在代码中实现业务拦截器的功能,是通过Spring提供的AOP来实现的,底层也就是基于动态代理及反射,这里看一下使用另一种不同的实现方式

如何优雅的遍历表中数据
日常工作中,有一些功能如状态更新等需要遍历表中数据,如果数据量比较少的情况下,我们可以正常的使用数据库如mysql提供的limit和offset来实现分页的功能,但是如果数据量比较大,这时候就会有深分页的问题,产生慢SQL, 为了解决这个问题,一种实现方式就是通过主键ID+查询条件来过滤数据,使用类似如下语句
1 | SELECT * FROM task WHERE id > $minId AND status = 1 ORDER BY id LIMIT 200 |
如果有其他条件导致需要扫描很大的行数才能扫描到的话,可能还需要限制id上限
1 | SELECT * FROM task WHERE id > $minId AND id < $maxId AND status = 1 ORDER BY id LIMIT 200 |
之后每次使用查询的最大值更新变量minId,直到查询不出数据为止,具体对应到Java代码中大致如下:
1 | public class TaskStatusUpdater { |
这里可以看到,执行方法中大部分都是一些业务无关的控制代码,如果有不同的处理逻辑需要遍历,那么都要复制一下这一大坨的控制代码,是否有更好的写法呢?
JSON处理神器-JSONata
让GPT开发Word模版功能
类GPT对于程序员来说比较大的用途之一就是可以用来生成代码,这次我们使用chatGpt来实现一个word的模版功能,也就是先使用一个word模版,然后使用对应的语法来将需要替换的地方使用占位符进行占位,在渲染的时候根据入参的数据进行替换,生成最终需要的word文件
预期需要支持一下几种模版语法功能:
- 简单字符串的替换
- 数字类型的小数截取功能,要支持位数不足时是否需要补0
- 需要支持日期的格式化
- 需要支持图片占位符的替换
- 需要支持使用对象集合,渲染word中表格多行的数据部分(暂未实现)
运行效果
先来看一下最终呈现的效果
word模版内容

模版使用数据
1 | Map<String, Object> placeholderMap = new HashMap<>(); |
最终word内容

JavaAgent使用及原理
在介绍Java agent之前,我们先来介绍一下一个比较关键的概念 - 字节码,这个如果大家已经比较熟悉了,可以直接跳到 java agent部分
字节码
我们知道Java编写的程序是可以不做任何修改的在不同的操作系统上面运行,也就是跨平台的,但是要想实现跨平台,就是需要能屏蔽掉不同操作系统之间api等的差异
比如说常见的创建线程,linux和window系统提供的接口就不一样
1 | // 不同操作系统下,使用c语言创建线程的API |
除了创建线程,其实还有很多的差异,比如说如果用C语言来实现既能在windows下运行,又能在linux下指定的代码,那么就需要针对有差异的地方,根据不同的操作系统来编写不同的代码,然后在编译的时候根据需要编译成对应系统下的二进制指令,这无疑是很痛苦和低效的方式
而Java下编译并不会生成目标平台的二进制文件,而是生成一个与平台无关的字节码文件,由不同平台下Java虚拟机负责加载执行,操作系统的差异就需要由虚拟机来进行屏蔽,对开发人员是无感知的
我们只需要将源代码编译成字节码(而不是操作系统下的二进制格式),剩下的就可以交给虚拟机来识别执行了

其实这样还有一个额外的好处,那就是在Java虚拟机上,不仅仅只能支持Java语言,理论上只要是符合规范的字节码文件,它都能执行,至于这个字节码文件是Java语言编译过来的,还是其他语言(如kotlin, groovy)编译过来的并不重要,甚至我们都可以手写字节码来执行~