XML规则代理实战:JQuick-Java接口绑定XML业务规则配置教程
前言
规则引擎落地时最常用的形态是:Java 接口声明契约、XML 文件承载规则、运行时自动生成动态代理——业务代码只依赖接口,规则内容完全外置。JQuick-Java 的 XML 规则代理正是这种形态的标准实现:接口方法名对应 XML 规则名,@Param 注解绑定脚本参数,createApi 一行生成代理。本文给出完整的 XML 规则代理配置教程与底层原理拆解。
核心技术原理
XML 规则代理的装配链路(源码位于 xml 包):
实战代码演示
1. 定义规则接口
public interface RulesMapper {
int scoreReportTime(@Param("eventType") String eventType,
@Param("reportMinutes") int reportMinutes);
double scoreCoordination(@Param("eventType") String eventType,
@Param("replyMinutes") int replyMinutes);
double calculateSingleEventScore(@Param("eventType") String eventType,
@Param("reportMinutes") int reportMinutes,
@Param("replyMinutes") int replyMinutes,
@Param("closureDays") int closureDays,
@Param("dispatchScore") int dispatchScore,
@Param("qualityScore") int qualityScore);
}
2. 编写 XML 规则文件(rules.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE javas PUBLIC "-//PAOHAIJIAO//DTD API JAVA 1.0//EN"
"classpath:paohaijiao/dtd/Jquick-java.dtd">
<javas namespace="com.github.paohaijiao.xml.RulesMapper">
<java name="scoreReportTime" returnClass="int">
<![CDATA[
int def scoreReportTime(str:eventType, int:reportMinutes) {
int score = 0;
int maxScore = 40;
int bonusScore = 10;
if (eventType == "A") {
if (reportMinutes <= 60) {
score = maxScore + (60 – reportMinutes) * bonusScore / 60;
} else if (reportMinutes <= 120) {
score = maxScore – (reportMinutes – 60) * 40 / 60;
} else {
score = 0;
}
}
if (score > 50) { score = 50; }
if (score < 0) { score = 0; }
return score;
}
]]>
</java>
<java name="calculateSingleEventScore" returnClass="double">
<![CDATA[
double def calculateSingleEventScore(str:eventType, int:reportMinutes,
int:replyMinutes, int:closureDays,
int:dispatchScore, int:qualityScore) {
int reportScore = this.scoreReportTime(eventType, reportMinutes);
double coordinationScore = this.scoreCoordination(eventType, replyMinutes);
int closureScore = this.scoreClosure(closureDays);
double totalScore = reportScore + coordinationScore + closureScore
+ dispatchScore + qualityScore;
if (totalScore > 100) { totalScore = 100; }
return totalScore;
}
]]>
</java>
</javas>
3. 生成代理并调用
RulesMapper mapper = JQuickJava.create()
.importPackage("java.lang.String", "str")
.createApi(RulesMapper.class, "rules.xml");
int reportScore = mapper.scoreReportTime("A", 20);
double total = mapper.calculateSingleEventScore("A", 20, 3, 1, 9, 4);
核心技术细节解析
- DTD 约束:Jquick-java.dtd 规定 javas 必须有 namespace 属性,java 必须有 name/returnClass 属性;内容可为 #PCDATA 或 if/foreach/choose 等动态标签,为规则拼接预留扩展。
- 参数类型简写:XML 中可用 str:xxx 简写(前提是接口绑定侧已 importPackage("java.lang.String","str")),也可写全限定名 java.lang.String:xxx。
- 脚本内调用同接口规则:函数体内用 this.scoreReportTime(eventType, reportMinutes) 调用同 namespace 的其他规则,实现规则编排(无需类型前缀)。
- 返回值按接口转换:脚本返回 double、接口声明 double,JQuickJavaTypeReference.of(method.getReturnType()) 保证类型一致。
常见踩坑与解决方案
最佳实践
- 每个业务域一个 XML 文件、一个 namespace,规则按 name 分类管理,便于维护与版本对比。
- 阈值类规则写在函数体顶部的变量(如 maxScore/bonusScore)中,集中修改。
- 代理实例创建成本主要在一次性的 XML 解析,规则不变时复用代理;变更时重新 createApi 即可热更新。
总结
JQuick-Java 的 XML 规则代理把「接口契约 + XML 配置 + 动态代理」三者串联,规则即配置、代理即入口,业务代码零规则逻辑。对需要把计分、校验、风控规则交给配置维护的团队,这是最标准的落地形态。



