动态代理核心原理:JQuick-Java接口规则自动生成机制解析

动态代理核心原理:JQuick-Java接口规则自动生成机制解析

前言

JQuick-Java 最优雅的设计是「接口即契约,规则自动挂载」:Java 侧只定义一个接口,XML/内联规则按方法名自动绑定,createApi 一行生成可用代理------没有注解扫描、没有代码生成器、没有 Spring 依赖。这背后是接口动态代理的自动生成机制。本文从 JQuickJavaXmlParseFactory 与代理工厂源码出发,解析接口规则自动生成的核心原理。

核心技术原理

接口代理的装配链路:

  1. 规则解析JQuickJavaXmlParseFactoryxml 包)创建 XML 解析工厂,JQuickXmlParser.parse(xmlPath)<javas namespace="接口全限定名"> 解析为 JQuickXmlNamespace,每个 <java> 成为一个 JQuickXmlMethod(含 name、returnClass、CDATA 内容);
  2. 代理生成JQuickXmlFactory.createApi(apiInterface) 基于 namespace 集合生成接口动态代理------内部为 JQuickAbsFactory 子类(XML 版 JQuickXmlFactory、内联版 JQuickInlineXmlFactory),持有 namespaceMap、context 与 JQuickXmlInvocationHandler
  3. 调用分发 :代理方法被调用时,JQuickJavaXmlInvocationHandler 按方法名找到 JQuickXmlMethod,执行「参数绑定 → 函数定义解析 → 执行 → 返回转换」;
  4. 内联合并createApiInternalrule() 注册的内联方法(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(方法名),代理调用按方法名路由,无需额外映射配置。
  • 返回类型对齐JQuickValueTransformermethod.getReturnType() 转换执行结果,脚本返回类型与接口声明不一致时会运行期报错(好过静默错值)。
  • 上下文注入createApi 时入口的 JContext 与环境变量经 JQuickJavaRuntimeEnvironment 注入执行链,代理调用天然可读取入口注入的变量。

常见踩坑与解决方案

  1. 接口方法多参时 @Param 缺失 :参数绑定依赖 @Param 注解或参数名,缺失时绑定 null;务必为每个参数声明 @Param("名称")
  2. namespace 与接口不匹配 :XML namespace 必须等于接口全限定名,否则代理调用找不到规则(方法返回 null 或抛异常)。
  3. 规则方法未定义 :接口方法在 XML 中没有同名 <java> 且无内联注册,调用时找不到 JQuickXmlMethod------请保证「接口方法 ⇔ 规则名」一一对应。

最佳实践

  • 优先使用 JQuickJava.createApi(...) 统一入口,底层工厂留给框架集成场景。
  • 接口方法与规则名严格对齐,命名即文档;必要时在接口注释中标注规则文件位置。
  • 代理实例复用(规则不变时不重建),解析与代理生成成本只在首次构建发生。

总结

JQuick-Java 的接口规则自动生成机制,用「namespace 定位 + 方法名路由 + 动态代理 + 参数/返回值对齐」四步,把「Java 接口 + 规则配置」无缝合成可调用的业务代理:零代码生成器、零扫描框架,规则即配置、代理即入口。对追求低侵入集成的团队,这是规则引擎落地的核心机制。

相关推荐
余槐i1 小时前
Firecrawl 实战:将网站转换为大模型可用数据
人工智能·python·工具·firecrawl
shirsl1 小时前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
步行cgn1 小时前
Spring 启动报错:BeanFactory not initialized 的原因与解决
java·python·spring
菜鸟~noob2332 小时前
【电子战】第08篇:多普勒测向的工程实现与优化【含matlab代码】
开发语言·matlab
步行cgn2 小时前
Spring 报错:No bean class specified on bean definition 的原因与解决
java·后端·spring
菜鸟~noob2332 小时前
【电子战】第06篇:干涉仪与相位差测向【含matlab代码】
开发语言·matlab
老王爱玩车2 小时前
深入理解指针2
c语言·开发语言·学习
quantdash_cc2 小时前
股票历史数据为什么比实时行情更重要?回测结果失真的根源可能就在 K 线数据
开发语言·python·数据分析·量化交易·股票数据·quantdash
光电的一只菜鸡2 小时前
为什么调整LSC会对AF产生影响
android·开发语言·kotlin