如何基于Java使用web3j库监听智能合约触发的事件
基于web3j监听智能合约链上事件的实现方案
前置准备
- 引入web3j核心依赖,Maven配置示例如下:
<dependency> <groupId>org.web3j</groupId> <artifactId>core</artifactId> <version>4.10.0</version> <!-- 可替换为最新稳定版 --> </dependency>
- 确认链节点RPC地址可用,长期监听场景优先选择支持WebSocket协议的节点地址。
- 如果使用合约包装类方案,需提前通过web3j命令行工具,将智能合约编译后的abi、bin文件生成对应的Java包装类。
具体实现
方式1:通过智能合约Java包装类监听(推荐)
web3j自动封装了事件解析逻辑,代码侵入性最低,适合有合约源码的场景,示例为监听ERC20合约的Transfer事件:
// 1. 初始化web3j实例,使用WebSocket适配长期监听场景 Web3j web3j = Web3j.build(new WebSocketService("ws://你的节点RPC地址", false)); // 2. 加载已部署的链上合约 ERC20 erc20 = ERC20.load( "0x合约地址", web3j, new DefaultTransactionManager(web3j), DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT ); // 3. 注册事件监听器,参数为监听的起始块、结束块 erc20.transferEventFlowable(DefaultBlockParameterName.LATEST, DefaultBlockParameterName.LATEST) .subscribe(event -> { // 直接获取解析完成的事件参数 String from = event.from; String to = event.to; BigInteger value = event.value; // 这里写业务逻辑 System.out.printf("监听到转账:%s 向 %s 转了 %d 个Token%n", from, to, value); }, error -> { // 异常处理,可在这里补充节点断开后的重连逻辑 System.err.println("监听异常:" + error.getMessage()); });
如果需要拉取历史区块的事件,可将起始块参数替换为对应的区块高度数值。
方式2:手动构造事件过滤器监听
没有合约Java包装类时可以用该方案,自行定义事件结构完成监听和解析:
// 1. 定义和合约一致的事件结构 Event transferEvent = new Event("Transfer", Arrays.asList( new TypeReference<Address>(true) {}, // 第一个indexed参数 new TypeReference<Address>(true) {}, // 第二个indexed参数 new TypeReference<Uint256>(false) {} // 非indexed参数 ) ); // 2. 构造事件过滤器 EthFilter filter = new EthFilter( DefaultBlockParameterName.LATEST, DefaultBlockParameterName.LATEST, "0x合约地址" // 不填则监听全网符合条件的事件 ); filter.addSingleTopic(EventEncoder.encode(transferEvent)); // 3. 注册监听器手动解析日志 web3j.ethLogFlowable(filter).subscribe(log -> { List<Type> nonIndexedParams = FunctionReturnDecoder.decode(log.getData(), transferEvent.getNonIndexedParameters()); String from = log.getTopics().get(1); String to = log.getTopics().get(2); BigInteger value = (BigInteger) nonIndexedParams.get(0).getValue(); // 这里写业务逻辑 System.out.printf("监听到转账:%s 向 %s 转了 %d 个Token%n", from, to, value); }, error -> { System.err.println("监听异常:" + error.getMessage()); });
注意事项
- 生产环境建议添加区块确认数校验,收到事件后等待1~6个区块确认再执行业务逻辑,避免链分叉导致数据失效。
- 大批量拉取历史事件时建议分块拉取,单次拉取区块范围不要超过1000块,避免节点响应超时。
- 必须添加异常重连机制,节点连接断开后自动重建监听,避免事件丢失。
内容的提问来源于stack exchange,提问作者shaikh47
相关产品推荐
相关产品推荐

