统一流程下的差异点解决方案-扩展点
我们都知道设计原则,追求开放封闭原则,封装变化 比如我们有一个统一的流程,运转良好且自认为设计的不错,这时来了个需求,说需要针对不同的来源要有一些特殊的处理,这时候我们如何支持呢? 一种简单的解决方案是加一个 if 判断,做一点特殊逻辑,但是这不是一个好的实践 这时候我们想到可以将这部分差异功能抽象为一个接口,然后有一种特殊的实现类还有一个默认的实现类。但是这时候另一个问题出现了,在执行到这部分逻辑的时候,如何确认使用哪个实现类呢(需要一个定位逻辑) 后面可能对于这个来源,还有一个地方需要处理,这时候又要有一套接口和定位逻辑 这时候我们可以考虑一下使用扩展点的方案,我们看下 COLA 提供的扩展点(示例来自源码) 首先引入一下依赖的包 12345<dependency> <groupId>com.alibaba.cola</groupId> <artifactId>cola-component-extension-starter</artifactId> <version>4.3.2<...
如何用非代理的方式实现java拦截器
《代码精进之路》中看到的拦截器实现,方式比较巧妙,在此记录一下 一般我们在代码中实现业务拦截器的功能,是通过Spring提供的AOP来实现的,底层也就是基于动态代理及反射,这里看一下使用另一种不同的实现方式 使用时需要先构建TargetInvocation, 设置好目标类的实现、入参以及具体的拦截器信息,之后将TargetInvocation当做要调用的目标类使用,直接进行调用即可 1234567891011121314public void test() { // 1. 构建TargetInvocation final TargetInvocation targetInvocation = new TargetInvocation(); // 2. 设置拦截器 targetInvocation.addInterceptor(new LogInterceptor()); targetInvocation.addInterceptor(new AuditInterceptor()); // 3. 设置请求参数 target...
如何优雅的遍历表中数据
日常工作中,有一些功能如状态更新等需要遍历表中数据,如果数据量比较少的情况下,我们可以正常的使用数据库如mysql提供的limit和offset来实现分页的功能,但是如果数据量比较大,这时候就会有深分页的问题,产生慢SQL, 为了解决这个问题,一种实现方式就是通过主键ID+查询条件来过滤数据,使用类似如下语句 1SELECT * FROM task WHERE id > $minId AND status = 1 ORDER BY id LIMIT 200 如果有其他条件导致需要扫描很大的行数才能扫描到的话,可能还需要限制id上限 1SELECT * FROM task WHERE id > $minId AND id < $maxId AND status = 1 ORDER BY id LIMIT 200 之后每次使用查询的最大值更新变量minId,直到查询不出数据为止,具体对应到Java代码中大致如下: 12345678910111213141516171819202122232425262728public class TaskStatusUpdater...
JSON处理神器-JSONata
之前介绍过 JSONPath 的使用,但是它只能支持一些简单场景下快速从json中获取指定的值,这次我们来看一款更强大的工具 JSONata,它是一种针对 JSON 数据的轻量级查询和转换语言,可以实现一些比较复杂的逻辑,现在我们就来看一下如何进行使用 先以一段json作为基础数据,看一下可以支持进行的操作 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647{ "FirstName": "Fred", "Surname": "Smith", "Age": 28, "Address": { "Street": "Hursley Park", "City": "Winchester", "Postcode&quo...
让GPT开发Word模版功能
类GPT对于程序员来说比较大的用途之一就是可以用来生成代码,这次我们使用chatGpt来实现一个word的模版功能,也就是先使用一个word模版,然后使用对应的语法来将需要替换的地方使用占位符进行占位,在渲染的时候根据入参的数据进行替换,生成最终需要的word文件 预期需要支持一下几种模版语法功能: 简单字符串的替换 数字类型的小数截取功能,要支持位数不足时是否需要补0 需要支持日期的格式化 需要支持图片占位符的替换 需要支持使用对象集合,渲染word中表格多行的数据部分(暂未实现) 运行效果 先来看一下最终呈现的效果 word模版内容 模版使用数据 12345678Map<String, Object> placeholderMap = new HashMap<>();placeholderMap.put("name", "张三");placeholderMap.put("profession", "里斯");placeholderMap.put("ssnam...
JavaAgent使用及原理
在介绍Java agent之前,我们先来介绍一下一个比较关键的概念 - 字节码,这个如果大家已经比较熟悉了,可以直接跳到 java agent部分 字节码 我们知道Java编写的程序是可以不做任何修改的在不同的操作系统上面运行,也就是跨平台的,但是要想实现跨平台,就是需要能屏蔽掉不同操作系统之间api等的差异 比如说常见的创建线程,linux和window系统提供的接口就不一样 1234567891011121314// 不同操作系统下,使用c语言创建线程的API// linuxint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void*), void *arg);// windowsHANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD...
Java异常重试-GuavaRetrying
重试在项目中还是比较常见的一个场景,比如调用外部服务因为网络等原因的异常,重试一次可能就成功了,而不需要立即给用户反馈错误,提高体验 假设我们自己来写一个最简单异常重试的话,可能代码是这样子的 123456789int retryTime = 3;for (int i = 0; i < retryTime; i++) { try { // 方法调用 return service.query(); } catch (Throwable e) { log.info("调用异常,进行重试"); }} 这里可能有几个问题需要考虑 不仅仅是异常需要重试,有时接口返回的特定错误码也是需要重试的 不是所有的异常都可以重试,需要根据情况判断异常原因才能重试 有时失败不能立即重试,需要等待一小段时间,比如短时网络波动 重试停止不一定只需要次数,有时也需要判断整体用的时间等因素 这么一看,需要考虑的地方还挺多,而重试功能又是一个非常通用的功能,所以完全...
Java项目中使用Groovy的几种方式
Groovy本身是一门完整的编程语言,同时也可以作为脚本集成到我们的应用中,为静态语言提供一些动态的能力,比如将 groovy 的脚本放到一些动态配置中或者数据库中进行管理,实现一些动态的规则计算等,在规则新增或变更的时候可以实时更新而无需开发代码上线,这次主要介绍一下Java中如何使用Groovy脚本 关于在应用中集成Groovy,官方文档已经提供了相关的资料,本次基于此文档进行一下说明 首先需要引入相应的包,这里基于的版本是3.0.16 12345<dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>3.0.16</version></dependency> Eval Eval是最简单的一种用法 12345678910111213141516171819import groovy.util.Eval;// 1.执行没有参数的...
Gson原理分析-JsonReader
java语言下,进行json处理的工具类jackson, fastjson, gson等,使用起来比较简单,就不介绍了,这次我们就来探索一下其中gson的具体实现,其核心处理类为JsonReader和JsonWriter进行json格式数据的读取和写入,上层TypeAdapter使用其进行json和具体数据类型的转换,而Gson调用时会根据类型获取到具体的TypeAdapter进行使用 在将json字符串转换成Java对象时,首先需要有定义Java的类,这里我们先不定义,而是使用一种更通用的,将json字符串转换成JsonElement的方法(com.google.gson.JsonParser#parseString)实现 123456789101112131415161718192021222324252627282930313233343536373839// JsonParser.javapublic static JsonElement parseReader(JsonReader reader) throws JsonIOException, Jso...
MyBatis(三)插件开发
MyBatis允许我们在其执行过程中对特定的一些方法进行拦截代理,实现一些特定的通用功能,如分页插件或者租户插件,允许进行拦截的类及对应方法基本如下 Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query) 这部分可以在源码中找到 12345678910111213141516171819202122232425262728293031323334353637383940// Configuration.javapublic ParameterHandler newParameterHandler(Ma...
