资讯动态

T100 ERP客制化实战:导入jar包并调用方法的完整指南

发布时间:2026/10/15 10:40:28 来源:尧图企业网站定制
简介这份文档面向使用鼎捷T100tiptop系统的Java开发与二次开发人员聚焦于在T100环境中导入外部jar包并成功调用其中方法这一常见需求。内容围绕XFTP上传jar包、修改CLASSPATH参数、重连ERP系统后import包、实例化对象并调用方法等关键环节展开并针对create方式报错的情况给出了在jar包内编写static静态getInstance方法返回实例对象的替代思路同时附有jar包内容与执行结果说明便于读者对照排查。资源包共1个docx文件约500KB以图文步骤形式记录完整操作过程适合具备一定4GL与Java基础的开发者参考。目前已有1223人学习可作为T100集成外部Java能力的实操参考帮助读者理解类路径配置与调用方式少走弯路。1. T100导入jar包并调用方法从“文档标题”到可复现的落地路径如果你正在看一份名为“T100导入jar包并调用jar包里的方法”的文档大概率你手里已经有一个封装好的 Java 工具类想把它塞进 T100 的客制化流程里跑起来。T100 是面向制造业的 ERP 开发平台它的客制化能力很强但强在“配置驱动”和“脚本扩展”而不是让你直接写一个完整的 Spring Boot 工程。所以“导入 jar 包并调用方法”这件事本质上是把外部编译好的 Java 逻辑通过 T100 提供的扩展机制挂载到单据、作业或批次任务上。适合谁适合已经能写 T100 客制化程序、但被“怎么把第三方 SDK 或自研工具类接进来”卡住的开发者。这篇不聊虚的直接按“放哪里、怎么引、怎么调、怎么排错”四步走中间会穿插我踩过的坑和参数边界。2. 先搞清楚 T100 的扩展边界为什么不能直接 new 一个对象2.1 T100 客制化程序的运行容器与类加载隔离T100 的客制化程序通常跑在它自己的服务端容器里这个容器对类加载做了隔离。你从外部拿到的 jar 包如果直接丢进某个公共 lib 目录大概率不会被客制化程序的类加载器扫描到。常见做法是把 jar 包放到 T100 服务端指定的扩展目录下然后在客制化程序的配置文件或注册入口里声明依赖。这里有个关键点——T100 不同版本对扩展目录的命名不一样有的叫extlib有的叫custom/lib还有的放在WEB-INF/lib下但需要重启服务。我一般会先确认三件事服务端启动脚本里CLASSPATH包含哪些目录、客制化程序编译时用的 classpath 是否和运行时一致、jar 包本身有没有依赖其他第三方库。如果 jar 包依赖了 T100 容器里没有的库比如某个 JSON 解析器或 HTTP 客户端你得把依赖一起放进去否则运行时报NoClassDefFoundError但编译期可能完全不报错这就是第一个玄学点。2.2 调用 jar 包方法的三种常见挂载方式在 T100 里调用外部 jar 的方法我见过三种落地方式。第一种是“客制化程序直接 import”前提是 jar 包已经被容器加载你可以在客制化程序的源码里直接写import com.xxx.Tool;然后调用静态方法。第二种是“反射调用”适合 jar 包不在编译期 classpath 里、但运行时能通过路径加载的场景用Class.forName加getMethod来调灵活但容易写错方法签名。第三种是“通过 T100 的扩展接口注册”比如实现某个Plugin接口把 jar 里的逻辑包装成 T100 能识别的服务再在作业里按服务名调用。第一种最直接第二种最灵活第三种最规范但改造成本高。我一般优先选第一种因为可读性好、调试方便如果 jar 包是动态上传的、不能重启服务才走反射。2.3 编译期与运行期 classpath 不一致的典型表现很多新手会卡在“编译通过、运行报错”上。原因很简单你在 IDE 里编译客制化程序时把 jar 包加到了项目的 build path 里但 T100 服务端运行时用的 classpath 是另一套。表现就是ClassNotFoundException或NoSuchMethodError。解决思路是先确认服务端实际加载了哪些目录再把 jar 包放到对应位置最后重启服务或触发类加载刷新。如果 T100 版本支持热加载可以省去重启但热加载对 jar 包内部依赖的刷新不一定彻底我遇到过改了 jar 里的常量值、热加载后还是旧值的情况最后只能重启。所以别偷懒该重启就重启。3. 把 jar 包放进 T100目录选择与依赖声明3.1 确认服务端扩展目录并放置 jar 包第一步是找到 T100 服务端真正会扫描的扩展目录。常见位置包括$T100_HOME/server/extlib、$T100_HOME/custom/lib、以及应用服务器如 Tomcat 或 Jetty的lib目录。你可以用find命令搜一下已有的第三方 jar 放在哪比如# 在 T100 安装目录下查找已有的第三方 jar 包位置 find /opt/t100 -name *.jar -path *lib* | head -20 # 查看服务启动脚本里 CLASSPATH 的定义 grep -r CLASSPATH /opt/t100/bin/*.sh逻辑说明第一条命令帮你定位现有 jar 的存放习惯第二条命令直接看启动脚本里 classpath 拼了哪些路径。参数说明/opt/t100换成你实际的安装根目录head -20只是防止输出太多实际排查时建议全看。如果启动脚本里用了-Djava.ext.dirs或-cp那 jar 包必须放在这些参数覆盖的目录下才生效。放好后别急着写代码先用一个最简单的测试类验证 jar 是否被加载。3.2 在客制化程序中声明依赖并编译假设你的 jar 包叫custom-utils.jar里面有个类com.demo.utils.StringHelper方法public static String trimAll(String input)。在 T100 客制化程序的源码里你需要先 import再调用// 客制化程序片段调用外部 jar 中的静态方法 import com.demo.utils.StringHelper; public class CustomJob { public void execute() { String raw hello t100 ; // 调用 jar 包里的静态方法注意方法签名要完全匹配 String result StringHelper.trimAll(raw); // 将结果写回 T100 的字段或日志 System.out.println(trim result: result); } }逻辑说明这段代码假设 jar 包已经在编译期 classpath 里。如果你在 IDE 里编译需要把custom-utils.jar加到项目的 Libraries 中如果你直接用 T100 自带的编译工具需要确认编译脚本的 classpath 包含该 jar。参数说明trimAll是静态方法所以直接用类名调用如果是实例方法得先new StringHelper()但 T100 客制化程序里 new 对象要注意生命周期别在循环里反复创建。编译成功后把 class 文件部署到 T100 对应目录重启服务。3.3 用反射方式调用未纳入编译期 classpath 的 jar如果 jar 包是后来动态放进去的编译期拿不到那就用反射。下面是一个反射调用的最小示例// 反射调用 jar 包中的方法适用于编译期无法 import 的场景 try { // 加载目标类注意包名和类名要完全正确 Class? clazz Class.forName(com.demo.utils.StringHelper); // 获取静态方法参数类型是 String.class java.lang.reflect.Method method clazz.getMethod(trimAll, String.class); // 静态方法 invoke 时第一个参数传 null Object result method.invoke(null, hello t100 ); System.out.println(reflect result: result); } catch (ClassNotFoundException e) { // jar 包没被加载到检查目录和重启 e.printStackTrace(); } catch (NoSuchMethodException e) { // 方法名或参数类型写错了用 javap 确认签名 e.printStackTrace(); } catch (Exception e) { // 方法内部抛出的异常看 cause e.printStackTrace(); }逻辑说明Class.forName会触发类加载如果 jar 不在运行时 classpath 里这里直接抛ClassNotFoundException。getMethod第二个参数是可变参数要按方法声明的参数类型逐个传比如String.class, int.class。invoke的第一个参数静态方法传null实例方法传对象实例。参数说明反射调用性能比直接调用差但差距在 T100 这种业务场景里可以忽略真正麻烦的是异常处理反射会把原始异常包在InvocationTargetException里你得用getCause()拿真实原因。4. 调用 jar 包方法时的参数传递与返回值处理4.1 基本类型、字符串与集合类的传参差异T100 客制化程序里的数据很多是从单据字段或数据库查询结果里来的类型可能是String、BigDecimal、Date或List。传给 jar 方法时要注意类型匹配。比如 jar 方法声明的是int你传String就会报IllegalArgumentException。常见做法是先用 T100 的内置函数做转换再传进去。如果 jar 方法接收的是ListMapString,Object而 T100 查询返回的是Vector或数组你得先转成ArrayList。我一般会在调用前加一层薄薄的适配代码把 T100 的数据结构转成 jar 期望的结构这样 jar 包本身不需要依赖 T100 的任何类保持干净。4.2 返回值如何写回 T100 字段或日志jar 方法返回的结果最终要落到 T100 的单据字段、临时表或日志里。如果是简单类型直接赋值给客制化程序的变量再通过 T100 的 API 写回。如果是复杂对象可能需要拆解成多个字段。这里有个坑T100 的字段有长度限制jar 返回的长字符串直接写回可能被截断甚至报错。我一般会先判断长度超长的截断或存到备注字段。另外如果 jar 方法返回null写回前要做空值处理否则 T100 的赋值 API 可能抛异常。日志方面建议用 T100 自己的日志接口而不是System.out因为服务端控制台日志滚动快排查时容易丢。4.3 异常传播与事务回滚的边界jar 方法内部抛异常时客制化程序要不要回滚事务这取决于你的业务场景。如果 jar 方法只是做数据校验抛异常后你可能想继续处理其他行如果 jar 方法参与核心数据写入抛异常就必须回滚。T100 的事务边界通常由客制化程序的框架控制你可以在 catch 块里决定是吞掉异常、包装后抛出还是触发回滚。注意反射调用时原始异常被包在InvocationTargetException里如果你直接把这个异常抛给 T100 框架框架可能不认识导致回滚行为不符合预期。正确做法是取出getCause()再决定怎么处理。5. 避坑与排查jar 包调用失败的 5 个血泪记录5.1 现象编译通过运行报 ClassNotFoundException原因jar 包没放在服务端运行时 classpath 覆盖的目录里或者放了但没重启服务。解决先用find确认 jar 位置再检查启动脚本的 classpath 参数最后重启 T100 服务。如果重启后还报用-verbose:class启动参数看类加载日志确认 jar 是否被扫描。5.2 现象NoSuchMethodError但方法明明存在原因jar 包有多个版本运行时加载了旧版本。T100 的扩展目录里可能残留了同名 jar 的旧版类加载器先加载了旧的。解决清理扩展目录里的重复 jar只保留一个版本用javap -classpath your.jar com.demo.utils.StringHelper确认方法签名和代码里的调用比对。5.3 现象反射调用时 IllegalArgumentException: argument type mismatch原因getMethod的参数类型和invoke传入的实参类型不匹配。比如方法声明是long你传了Integer。解决反射调用前把参数转成精确类型比如((Number) value).longValue()。另外基本类型和包装类型在反射里不自动装箱必须严格对应。5.4 现象jar 方法内部报 NoClassDefFoundError指向另一个第三方类原因jar 包依赖了其他库但那些库没一起放进去。解决用jdeps或mvn dependency:tree分析 jar 的依赖把所有运行时需要的 jar 都放进扩展目录。如果依赖冲突比如两个 jar 依赖了同一个库的不同版本优先保留高版本并测试兼容性。5.5 现象热加载后 jar 里的常量还是旧值原因T100 的热加载机制对 jar 包内部的类刷新不彻底尤其是静态常量在类初始化时已经赋值。解决别依赖热加载改完 jar 直接重启服务。如果业务不允许频繁重启就把可变参数外置到配置文件jar 方法每次从配置读取而不是写死在代码里。6. 进阶把 jar 包调用封装成可复用的 T100 服务6.1 用工厂模式隔离 jar 加载与业务调用如果你要在多个客制化程序里调用同一个 jar别在每个程序里都写一遍Class.forName。我一般会写一个简单的工厂类把 jar 的加载和调用封装起来。工厂类里用静态块加载一次对外暴露业务方法。这样业务代码只依赖工厂接口不直接依赖 jar 的类名。将来 jar 升级或换实现只改工厂类。下面是一个最小工厂示例// 工厂类封装 jar 包的加载与调用业务代码不直接依赖 jar public class JarServiceFactory { private static Class? helperClass; static { try { // 只加载一次避免重复反射开销 helperClass Class.forName(com.demo.utils.StringHelper); } catch (ClassNotFoundException e) { throw new RuntimeException(jar not loaded, check extlib and restart, e); } } // 对外暴露的业务方法内部走反射 public static String trim(String input) { try { java.lang.reflect.Method m helperClass.getMethod(trimAll, String.class); return (String) m.invoke(null, input); } catch (Exception e) { throw new RuntimeException(invoke trimAll failed, e); } } }逻辑说明静态块保证类加载时只执行一次Class.forName后续调用直接复用helperClass。业务方法trim把反射的异常统一包成RuntimeException调用方不用处理一堆受检异常。参数说明如果 jar 方法有多个重载getMethod要传精确的参数类型如果方法不是静态的工厂里还得维护实例注意线程安全。6.2 用配置文件管理 jar 路径与类名硬编码类名和路径不利于维护。我习惯在 T100 的客制化配置文件里加一段# custom-jar.properties custom.jar.classcom.demo.utils.StringHelper custom.jar.methodtrimAll custom.jar.paramTypejava.lang.String然后在工厂类里用Properties加载反射时动态取类名和方法名。这样换 jar 或换方法时只改配置文件不用重新编译客制化程序。注意配置文件要放在 T100 能读到的路径下并且编码用 UTF-8避免中文注释乱码。6.3 验证 jar 是否被正确加载的三种手段第一种在客制化程序启动时打印helperClass.getClassLoader()看是哪个类加载器加载的和 T100 主程序的类加载器是否一致。第二种用Class.forName加载后调用getDeclaredMethods()打印所有方法签名确认方法存在。第三种写一个最简单的main方法在 T100 服务端用java -cp手动跑一下排除客制化框架的干扰。我一般先跑第三种确认 jar 本身没问题再排查 T100 的类加载。最后说个习惯每次改完 jar 或配置先重启服务再跑一个最小用例别一上来就全流程测试否则报错信息混在一起排查成本翻倍。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑