如何在不停止应用程序的情况下在骆驼路线中使用动态或重新启动路线

How to use dynamic from in Camel route or restart route without stopping application

我有现有的 Spring 启动应用程序,它使用 Camel 框架从不同文件夹获取数据。所有路由以类似方式轮询数据:

from(fileUriWithCurrentDay(path, config.getParams())).routeId(ROUTE_ID)

其中方法定义如下:

public static String fileUriWithCurrentDay(String path, Map<String, String> params) {
path = path.endsWith(SEPARATOR) ? path : path + SEPARATOR;
return "file:" + path + currentDayPath() + fileParams(params);
}

和 returns 取决于日期:

c:/test/data/2021/242?noop=true&idempotent=false&autoCreate=false&includeExt=xml&scheduler=spring&scheduler.cron = "0 0 13 ? * *"

cron 设置为每天启动一次。当达到 cron time 时,路由开始执行其工作并正确完成。但是第二天它开始轮询同一个文件夹,例如242 但应该是 243.

所以问题是:从端点应该在开始时动态计算。

我从 Camel 中读到过有关 dynamic 的信息,但没有找到任何信息表明这种选项是开箱即用的。 我尝试使用计算出的 header 来使用 pollEnrich() 选项,但它似乎不支持动态端点,因为 returns 下一个错误:

org.apache.camel.ResolveEndpointFailedException Dynamic expressions with ${ } placeholders is not allowed. Use the fileName option to set the dynamic expression.

路由启动后如何刷新from endpoint?

我也看到了 2 种可能的解决方案,但不知道是否有帮助:

  1. 重新启动路由以从端点 uri 重新计算。
  2. 重新启动整个 Camel 上下文。目前所有路线都标记为Spring @Component.

与其他 EIP 组件不同,routeId 和 from endpoint 中的字符串在创建路由后是固定的(除非您使用另一个 from endpoint url 重新创建路由)。因此,有 2 个可能的前进方向。一种方法是从端点 url 重新创建路由,另一种方法是在组件中查找参数以支持您的操作。

  1. 在相同的 CamelContext

    中重新创建具有相同 routeId 的消费者路由
    • 每天触发以下操作(例如使用 timer 路线)
    • 使用 RouteBuilder 构建路由配置(具有相同的消费者路由 ID 和来自端点 url 的新路由 ID)
    • 使用 CamelContext class 的 addRoutes 方法和新路由配置
    • 重新创建路由
  2. file component

    中利用filterDirectory
    • 将文件路径设置为公共根文件夹(即 c:/test/data
    • 启用recursive查找子目录
    • 使用filterDirectory根据simple语言过滤目录
      • simple language documentation开始,简单语言的日期命令正在使用java.text.SimpleDateFormat
      • Oracle doc 开始,SimpleDateFormat 支持年份和年份中的日期(假设您的示例中的 242 和 243 是年份中的日期)

免责声明

我之前没有用过filterDirectory,方法2是从Camel文档中推导出来的。

查看 File 组件的文档,您尝试执行的操作仅使用起始点 URI 是不可能的。

我建议在 URI 中使用一个公共基目录,并创建一个 GenericFileFilter 的实现,您将与源端点一起使用。它允许在实现处理文件和不处理文件的逻辑方面有很大的自由度。

要从 base/path/2021 读取文件,请创建如下内容:


@Component
public class FileFilter<T> implements GenericFileFilter<T> {
    @Override
    public boolean accept(GenericFile<T> file) {
        if (file.isDirectory()) {
            return "2021".equals(file.getFileName());
        }
        return file.getFileName().startsWith("2021/");
    }
}

端点 URI 如下:

file://base/path?recursive=true&filter=#fileFilter

在实现 GenericFileFilter 时,您应该注意 accept() 也会为目录调用。