Camel SFTP文件下载问题:文件已复制但路由未关闭重复拉取
解决Camel SFTP路由重复拉取文件的问题
问题描述
搭建了API服务,调用API时通过Camel集成器从外部SFTP服务器下载文件,目前文件已成功复制到本地,但SFTP路由未自动关闭,会持续重复拉取服务器上的文件。
现有代码片段
API代码
@GetMapping("myapicall") public void fetchFileFromSFTPServer() { logger.info("-------Begin of fetchFileFromSFTPServer-------"); try { RouteBuilder routeBuilder = sftpRoute.buildRoute(); camelContext.addRoutes(routeBuilder); } catch (Exception e) { logger.error("Error while loading Routes------" + e.getMessage()); } camelContext.setUseMDCLogging(true); logger.info("-------End of fetchFileFromSFTPServer-------" ); }
路由构建器代码
public RouteBuilder buildRoute() { RouteBuilder builder = new RouteBuilder() { @Override public void configure() throws Exception { from( "sftp://server/?username=**&password=**&passiveMode=true&disconnect=true") .routeId("SFTP_File_Route").setExchangePattern(ExchangePattern.InOnly). log("connecting to SFTP Server") .to("file://C:/myLocal").end(); } }; return builder; }
问题根源
Camel的SFTP组件默认采用轮询消费模式,添加路由后会定期检查SFTP服务器并拉取文件,不会自动停止,因此出现重复拉取的情况。
解决方案
方法1:修改SFTP URI参数,实现一次性拉取
在SFTP的URI中添加参数,让路由仅执行一次轮询就停止:
- 添加
consumer.delay=-1:表示仅轮询一次,完成后停止路由 - 或组合使用
consumer.maxMessagesPerPoll=1(每次轮询最多拉取1个文件)、stopOnIdleTimeout=true(空闲超时后停止)和idleTimeout=5000(设置5秒空闲超时)
修改后的SFTP URI示例:
sftp://server/?username=**&password=**&passiveMode=true&disconnect=true&consumer.delay=-1
方法2:手动停止并移除路由
在API中等待文件下载完成后,手动停止并移除对应路由,避免持续轮询。修改后的API代码示例:
@GetMapping("myapicall") public void fetchFileFromSFTPServer() { logger.info("-------Begin of fetchFileFromSFTPServer-------"); try { String routeId = "SFTP_File_Route"; // 检查路由是否已存在,避免重复添加冲突 if (!camelContext.getRouteDefinitions().stream().anyMatch(rd -> rd.getId().equals(routeId))) { RouteBuilder routeBuilder = sftpRoute.buildRoute(); camelContext.addRoutes(routeBuilder); } // 等待路由执行完成(实际场景建议用Camel事件监听或异步回调,此处用sleep做简单示例) Thread.sleep(3000); // 停止并移除路由 if (camelContext.getRouteStatus(routeId).isStarted()) { camelContext.stopRoute(routeId); camelContext.removeRoute(routeId); } } catch (Exception e) { logger.error("Error while loading Routes------" + e.getMessage()); } camelContext.setUseMDCLogging(true); logger.info("-------End of fetchFileFromSFTPServer-------" ); }
方法3:使用ProducerTemplate触发一次性传输(推荐)
避免动态添加路由,直接用ProducerTemplate触发一次性文件传输,完成后自动结束,无需持续轮询。示例代码:
@Autowired private ProducerTemplate producerTemplate; @GetMapping("myapicall") public void fetchFileFromSFTPServer() { logger.info("-------Begin of fetchFileFromSFTPServer-------"); try { // 直接触发从SFTP到本地的一次性传输 producerTemplate.send( "sftp://server/?username=**&password=**&passiveMode=true", exchange -> { // 指定要下载的文件名,*表示下载所有文件 exchange.getIn().setHeader("CamelFileName", "*"); }, "file://C:/myLocal" ); } catch (Exception e) { logger.error("Error while fetching file------" + e.getMessage()); } logger.info("-------End of fetchFileFromSFTPServer-------" ); }
内容的提问来源于stack exchange,提问作者Lokesh Deena
相关产品推荐
相关产品推荐

