简介:这份资源面向从事工业自动化与监控系统开发的 Java 工程师,尤其是需要基于 openSCADA 搭建数据采集、OPC 通信或上位机监控项目的开发者。它汇集了 openSCADA 开发过程中所需的全部依赖 jar 包,省去逐个查找、版本比对与手动下载的繁琐环节,可直接导入工程使用。压缩包共 480 个文件,约 30.92MB,其中 129 个 jar 为核心依赖库,339 个 class 为编译产物,另含少量 xml、properties、classpath 等配置与工程描述文件,以及 dll 动态库,覆盖运行与构建所需的主要环节。目前已有 688 人学习下载,说明该依赖集合在实际项目中具备一定参考价值。对于初次接触 openSCADA 或需要快速补齐 OPC 通信依赖的开发者,这份资源能帮助缩短环境搭建时间,降低因缺包、版本冲突导致的编译与运行报错概率,也便于对照目录结构理解各模块的依赖关系。
1. 从一次现场联调说起:openSCADA 的 jar 依赖到底卡在哪
上个月帮一个做水处理监控的团队排查问题,现场工程师反馈:组态画面能跑,但 OPC 采集进程一启动就抛NoClassDefFoundError,日志里翻来覆去就是几个包名。他们手里拿到的是一份 openSCADA 的二次开发包,里面散落着几十个 jar,谁也不敢删,谁也不知道哪个是必须的。这个场景其实很典型——openSCADA 本身是 Java 写的工业组态/SCADA 平台,核心能力包括实时库、历史库、报警、报表和 OPC UA/DA 采集,而它的运行完全依赖一套 jar 依赖树。你拿到的这份资源,就是把这套依赖整理清楚,让你在离线环境、内网部署或者做二次开发时,不用再去一个个猜哪个 jar 对应哪个模块。适合谁?做工业数据采集的 Java 后端、需要把 openSCADA 嵌进自有系统的集成商,以及被 jar 冲突折磨过的运维。下面我按实际拆包顺序讲。
2. 拆开依赖树:openSCADA 的 jar 分哪几类,各自干什么
2.1 核心运行时 jar:没有它们连启动都过不去
openSCADA 的 Java 实现里,最底层是平台自身的核心包,通常以openscada-core、openscada-utils、openscada-db这类命名出现。它们负责的东西很实在:实时数据模型、访问控制、日志框架、数据库连接池的抽象层。你如果只做 OPC 采集,也绕不开这几个,因为采集进程本身要注册到实时库里。
我一般会先把 jar 按包名前缀分堆,而不是按文件名。因为很多二次开发包会把版本号写在文件名里,比如openscada-core-0.9.2.jar,但实际依赖关系看的是包名。分堆之后你会发现,核心运行时大概占三分之一,剩下的是模块和第三方库。
判断一个 jar 是不是核心,有个笨但有效的办法:把它临时移出 classpath,启动一个最小实例,看报错是不是ClassNotFoundException指向org.openscada.core或org.openscada.utils。如果是,那它就是核心。这个办法比看文档快,因为文档经常和实际版本对不上。
2.2 协议与采集模块 jar:OPC 采集真正用到的那些
关键词里提到 OPC,这是 openSCADA 在工业现场最常用的采集协议之一。对应的 jar 通常包含openscada-protocol-opc、openscada-protocol-opcua以及底层依赖的 OPC 库,比如某些实现会依赖opcua-stack或jinterop这类第三方包。这里有个容易翻车的点:OPC DA 和 OPC UA 的依赖完全不同。DA 走的是 Windows COM/DCOM 桥接,Java 侧一般靠 JInterop;UA 走的是 TCP 二进制协议,靠的是纯 Java 的 stack。
如果你现场是 OPC UA,却把 DA 的 jar 也塞进 classpath,通常不会立刻报错,但会在建立连接时出现超时或者UnsatisfiedLinkError。我遇到过一回,现场工程师把两个协议的 jar 全放进去了,结果 UA 连接一直重试,日志里却只显示“连接被拒绝”,查了两天才发现是 DA 的本地库在干扰。
所以我的习惯是:按协议分目录,UA 一个 lib 目录,DA 一个 lib 目录,启动脚本里用-cp显式指定,而不是用通配符lib/*。这样虽然麻烦一点,但排错时能省掉大量玄学时间。
2.3 第三方依赖 jar:版本冲突的重灾区
openSCADA 依赖的第三方库不少,常见的有日志(slf4j、log4j)、数据库驱动(JDBC)、网络(Netty)、序列化(Jackson)等。这些 jar 的版本冲突是导致NoSuchMethodError和AbstractMethodError的主要原因。比如 Netty 的 4.0 和 4.1 在 API 上有差异,如果 openSCADA 编译时用的是 4.1,而你 classpath 里混入了 4.0,启动时可能不报错,但一走到 OPC UA 的握手阶段就崩。
处理这类问题的标准做法是:用mvn dependency:tree或者gradle dependencies把依赖树打出来,找到冲突的 artifact,然后在构建文件里用<exclusions>排除掉旧版本。如果你拿到的资源里已经带了pom.xml或者build.gradle,那最好不过,直接看里面的依赖声明。如果没有,就只能靠jdeps或者手动比对 jar 里的META-INF/MANIFEST.MF。
提示:不要用
java -jar直接跑 openSCADA 的主 jar,除非它明确写了 Main-Class 并且所有依赖都打进了 fat jar。工业现场更常见的是用脚本组装 classpath,这样可控性更高。
3. 把 jar 用起来:从零搭建一个可运行的 OPC 采集环境
3.1 环境准备与目录规划
假设你拿到的是一个压缩包,解压后有一堆 jar 和少量配置文件。我建议先建一个干净的目录结构,不要直接在解压目录里改。下面是我常用的布局:
# 建立工作目录 mkdir -p /opt/openscada-demo/{lib-core,lib-opcua,lib-thirdparty,conf,logs} # 把核心 jar 放进 lib-core cp openscada-core-*.jar openscada-utils-*.jar openscada-db-*.jar /opt/openscada-demo/lib-core/ # 把 OPC UA 相关 jar 放进 lib-opcua cp openscada-protocol-opcua-*.jar opcua-stack-*.jar /opt/openscada-demo/lib-opcua/ # 第三方依赖单独放,方便排查冲突 cp slf4j-api-*.jar log4j-*.jar netty-*.jar jackson-*.jar /opt/openscada-demo/lib-thirdparty/这样分的好处是,启动脚本里可以按需组合。比如只做 OPC UA 采集时,classpath 就是lib-core:lib-opcua:lib-thirdparty,不会误引入 DA 的本地库。参数上,-cp后面的路径用冒号分隔(Linux)或分号(Windows),顺序不重要,但同一个包的不同版本不要同时出现。
3.2 启动脚本与 JVM 参数
openSCADA 在工业现场通常需要长时间运行,所以 JVM 参数不能省。下面是一个我常用的启动脚本片段:
#!/bin/bash # openSCADA OPC UA 采集进程启动脚本 BASE_DIR=/opt/openscada-demo CP="$BASE_DIR/lib-core/*:$BASE_DIR/lib-opcua/*:$BASE_DIR/lib-thirdparty/*" # 关键 JVM 参数说明: # -Xms512m -Xmx1024m:堆内存初始和最大,工业现场数据点多了要调大 # -XX:+UseG1GC:G1 在长时间运行下比 CMS 稳,减少 Full GC 停顿 # -Dlog4j.configuration=file:$BASE_DIR/conf/log4j.properties:指定日志配置 # -Dopenscada.home=$BASE_DIR:告诉 openSCADA 配置和日志放哪 java -Xms512m -Xmx1024m -XX:+UseG1GC \ -Dlog4j.configuration=file:$BASE_DIR/conf/log4j.properties \ -Dopenscada.home=$BASE_DIR \ -cp "$CP" \ org.openscada.opcua.server.Bootstrap \ > $BASE_DIR/logs/stdout.log 2>&1 &这里org.openscada.opcua.server.Bootstrap是示例入口类,实际类名要看你的 jar 里META-INF/MANIFEST.MF的Main-Class或者文档。如果找不到入口类,可以用jar tf xxx.jar | grep -i bootstrap来搜。参数方面,-Xmx不要超过物理内存的 70%,因为 OPC 采集还要留内存给操作系统和网络缓冲。G1 的-XX:MaxGCPauseMillis可以设成 200,但别设太小,否则 GC 线程会抢 CPU。
3.3 配置文件与 OPC 连接参数
openSCADA 的 OPC UA 采集配置通常是一个 XML 或 properties 文件,放在conf目录下。下面是一个最小化的 OPC UA 连接配置示例:
<!-- opcua-connection.xml --> <connection> <!-- 端点 URL,格式为 opc.tcp://主机:端口 --> <endpoint>opc.tcp://192.168.1.100:4840</endpoint> <!-- 安全策略,现场内网常用 None,跨网段建议 SignAndEncrypt --> <securityPolicy>None</securityPolicy> <!-- 会话超时,单位毫秒,默认 60000 --> <sessionTimeout>120000</sessionTimeout> <!-- 订阅发布间隔,单位毫秒,采集频率高的点可以调小 --> <publishingInterval>1000</publishingInterval> <!-- 要采集的节点 ID 列表 --> <items> <item>ns=2;s=Temperature</item> <item>ns=2;s=Pressure</item> </items> </connection>参数说明:endpoint必须和 OPC UA 服务器实际暴露的地址一致,如果服务器在另一台机器,注意防火墙放行 4840 端口。securityPolicy设为 None 时不需要证书,适合调试;生产环境如果跨网段,建议用 SignAndEncrypt,但那就需要额外配置证书,jar 里通常也带了bcprov之类的加密库。publishingInterval不是越小越好,设成 100ms 以下时,服务器和网络压力会明显上升,除非你的点变化非常快。
3.4 验证采集是否成功
启动后,不要只看进程在不在,要看日志和实时库。我一般会做三步验证:
第一步,看 stdout 日志里有没有Session created和Subscription created。如果没有,说明连接没建立,回去检查 endpoint 和防火墙。
第二步,用 openSCADA 自带的客户端工具或者一个简单的 Java 程序读一下实时库里的值。下面是一个用 JDBC 风格读实时库的示例(具体 API 看你的版本):
// 读取实时库中的 OPC 采集值 import org.openscada.core.Variant; import org.openscada.da.client.DataItemValue; import org.openscada.da.client.Connection; public class ReadDemo { public static void main(String[] args) throws Exception { // 连接到本地 openSCADA 实时库 Connection connection = new Connection("tcp://localhost:2101"); connection.connect(); // 读取之前配置的节点 DataItemValue value = connection.getItem("ns=2;s=Temperature"); Variant v = value.getValue(); System.out.println("Temperature = " + v); connection.disconnect(); } }这段代码的关键是Connection的地址和端口,默认是 2101,但你的环境可能改过。如果读不到值,先确认采集进程是否真的把数据写进了实时库,而不是只建立了 OPC 连接。有时候 OPC 连上了,但订阅没生效,实时库里就是空的。
第三步,观察一段时间,看日志里有没有Reconnect或者Timeout。工业现场网络抖动很常见,openSCADA 一般有重连机制,但如果重连太频繁,就要检查网络质量或者把sessionTimeout调大。
4. 避坑指南:jar 依赖和 OPC 采集的五个常见翻车点
4.1 现象:启动时报NoClassDefFoundError: org/openscada/core/...
原因:核心运行时 jar 没放全,或者被其他版本的 jar 覆盖了。常见于从不同地方拷贝 jar 时,只拷了openscada-core却漏了openscada-utils。 解决:用jar tf确认每个核心 jar 里的包路径,确保org/openscada/core和org/openscada/utils都存在。如果版本不一致,统一到同一个版本号。
4.2 现象:OPC UA 连接时抛出UnsatisfiedLinkError或NoSuchMethodError
原因:classpath 里混入了 OPC DA 的本地库,或者 Netty 版本冲突。DA 的 JInterop 会加载.dll或.so,在 Linux 上直接失败;Netty 版本冲突则会在握手时调用不存在的方法。 解决:按协议分目录,启动脚本里不要用lib/*通配符。用mvn dependency:tree找出冲突的 Netty 版本,在构建文件里排除旧版本。
4.3 现象:采集进程运行几小时后内存溢出,日志里OutOfMemoryError: Java heap space
原因:-Xmx设得太小,或者 OPC 订阅项太多导致实时库缓存膨胀。openSCADA 的实时库会保留一定历史值,如果订阅了几万个点,内存增长会很快。 解决:先把-Xmx调到 2G 以上,观察是否还溢出。如果还溢出,检查订阅列表,把不必要的高频点去掉,或者调大publishingInterval。另外,G1 的-XX:InitiatingHeapOccupancyPercent可以设成 40,让并发标记更早启动。
4.4 现象:OPC 连接成功但读不到数据,实时库里值为空
原因:节点 ID 写错了,或者 OPC 服务器上的节点权限不够。openSCADA 的 OPC UA 客户端默认用匿名登录,如果服务器要求用户名密码,就会连上但读不到。 解决:先用 UaExpert 之类的通用客户端验证节点 ID 和权限,确认能读到值后再配到 openSCADA 里。如果服务器要求认证,在连接配置里加上用户名密码字段。
4.5 现象:日志里大量Reconnect,采集时断时续
原因:网络不稳定,或者sessionTimeout设得太短。工业现场交换机负载高时,OPC UA 的 KeepAlive 包可能丢失,导致会话被服务器断开。 解决:把sessionTimeout从默认的 60000 调到 120000 或更长,同时在网络层面检查丢包率。如果用的是无线网络,尽量改成有线。
5. 进阶:用 Maven 管理 openSCADA 依赖,以及一个验证 jar 完整性的习惯
如果你不是直接拿 jar 包,而是想在自己的项目里引用 openSCADA,那用 Maven 管理依赖会省心很多。openSCADA 的 artifact 通常发布在私有仓库或者中央仓库的某个 groupId 下,你可以在pom.xml里声明:
<dependency> <groupId>org.openscada</groupId> <artifactId>openscada-core</artifactId> <version>0.9.2</version> <!-- 版本号以你实际拿到的为准 --> </dependency> <dependency> <groupId>org.openscada</groupId> <artifactId>openscada-protocol-opcua</artifactId> <version>0.9.2</version> <exclusions> <!-- 排除旧版 Netty,避免冲突 --> <exclusion> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> </exclusion> </exclusions> </dependency>这样 Maven 会自动拉取传递依赖,你只需要处理冲突。但离线环境就不行了,所以我还是会保留一份手动整理的 jar 目录,作为兜底。
另外,我养成了一个习惯:每次拿到新的 jar 包,先算一遍 SHA-256,和资源里附带的校验文件比对。工业现场最怕的就是 jar 在拷贝过程中损坏,表面看文件大小一样,但运行时就是各种诡异错误。下面这个命令我每次都会跑:
# 计算所有 jar 的 SHA-256 并保存 find /opt/openscada-demo -name "*.jar" -exec sha256sum {} \; > /opt/openscada-demo/jars.sha256 # 下次部署时校验 sha256sum -c /opt/openscada-demo/jars.sha256如果校验失败,说明文件在传输中出了问题,重新拷贝比排查运行时错误快得多。这个习惯帮我省过至少两次通宵——有一次现场部署,一个核心 jar 的字节被截断了,启动时报的错完全指向另一个模块,查了半天才发现是文件损坏。
从那以后,我每次部署 openSCADA 之前,都会强制走一遍 jar 完整性校验和 classpath 冲突检查,哪怕现场再急也不跳过。希望帮到你。
本文还有配套的精品资源,点击获取