动态代理核心原理:JQuick-Java接口规则自动生成机制解析
前言
JQuick-Java 最优雅的设计是「接口即契约,规则自动挂载」:Java 侧只定义一个接口,XML/内联规则按方法名自动绑定,createApi 一行生成可用代理------没有注解扫描、没有代码生成器、没有 Spring 依赖。这背后是接口动态代理的自动生成机制。本文从 JQuickJavaXmlParseFactory 与代理工厂源码出发,解析接口规则自动生成的核心原理。
核心技术原理
接口代理的装配链路:
- 规则解析 :
JQuickJavaXmlParseFactory(xml包)创建 XML 解析工厂,JQuickXmlParser.parse(xmlPath)把<javas namespace="接口全限定名">解析为JQuickXmlNamespace,每个<java>成为一个JQuickXmlMethod(含 name、returnClass、CDATA 内容); - 代理生成 :
JQuickXmlFactory.createApi(apiInterface)基于 namespace 集合生成接口动态代理------内部为JQuickAbsFactory子类(XML 版JQuickXmlFactory、内联版JQuickInlineXmlFactory),持有 namespaceMap、context 与JQuickXmlInvocationHandler; - 调用分发 :代理方法被调用时,
JQuickJavaXmlInvocationHandler按方法名找到JQuickXmlMethod,执行「参数绑定 → 函数定义解析 → 执行 → 返回转换」; - 内联合并 :
createApiInternal把rule()注册的内联方法(tag = "inline")合并进对应 namespace,同名时内联覆盖 XML。
实战代码演示
1. 接口定义(无需任何注解约束方法名之外的额外配置)
java
public interface UserMapper {
int sum(@Param("a") int a, @Param("b") int b);
int mul(@Param("a") int a, @Param("b") int b);
}
2. XML 规则(jquick-java.xml)
xml
<javas namespace="com.github.paohaijiao.xml.UserMapper">
<java name="sum" returnClass="java.util.List">
<![CDATA[
int def sum(int:a,int:b) {
return a+b;
}
]]>
</java>
</javas>
3. 生成代理(三种入口殊途同归)
java
// 方式一:统一入口(推荐)
UserMapper api1 = JQuickJava.create().createApi(UserMapper.class, "jquick-java.xml");
// 方式二:底层工厂
JQuickJavaXmlParseFactory handler = new JQuickJavaXmlParseFactory();
JQuickFactory factory = new JQuickXmlFactory(handler, "jquick-java.xml");
UserMapper api2 = factory.createApi(UserMapper.class);
// 方式三:纯内联(无 XML)
UserMapper api3 = JQuickJava.create()
.rule("sum", "int def sum(int:a,int:b){ return a+b; }")
.rule("mul", "int def mul(int:a,int:b){ return a*b; }")
.createApi(UserMapper.class);
assertEquals(3, api1.sum(1, 2));
assertEquals(3, api2.sum(1, 2));
assertEquals(12, api3.mul(3, 4));
核心技术细节解析
- namespace 即接口定位 :代理按
apiInterface.getName()(全限定名)在 namespaceMap 中查找规则;找不到 namespace 时,纯内联场景会动态创建(JQuickXmlBuilder.create().namespace(...))。 - 方法名即规则名 :
JQuickXmlMethod.setName(方法名),代理调用按方法名路由,无需额外映射配置。 - 返回类型对齐 :
JQuickValueTransformer按method.getReturnType()转换执行结果,脚本返回类型与接口声明不一致时会运行期报错(好过静默错值)。 - 上下文注入 :
createApi时入口的JContext与环境变量经JQuickJavaRuntimeEnvironment注入执行链,代理调用天然可读取入口注入的变量。
常见踩坑与解决方案
- 接口方法多参时
@Param缺失 :参数绑定依赖@Param注解或参数名,缺失时绑定 null;务必为每个参数声明@Param("名称")。 - namespace 与接口不匹配 :XML
namespace必须等于接口全限定名,否则代理调用找不到规则(方法返回 null 或抛异常)。 - 规则方法未定义 :接口方法在 XML 中没有同名
<java>且无内联注册,调用时找不到JQuickXmlMethod------请保证「接口方法 ⇔ 规则名」一一对应。
最佳实践
- 优先使用
JQuickJava.createApi(...)统一入口,底层工厂留给框架集成场景。 - 接口方法与规则名严格对齐,命名即文档;必要时在接口注释中标注规则文件位置。
- 代理实例复用(规则不变时不重建),解析与代理生成成本只在首次构建发生。
总结
JQuick-Java 的接口规则自动生成机制,用「namespace 定位 + 方法名路由 + 动态代理 + 参数/返回值对齐」四步,把「Java 接口 + 规则配置」无缝合成可调用的业务代理:零代码生成器、零扫描框架,规则即配置、代理即入口。对追求低侵入集成的团队,这是规则引擎落地的核心机制。