【问题标题】:How to create routes configuration itself dynamically如何动态创建路由配置本身
【发布时间】:2019-05-16 16:41:11
【问题描述】:

在我的一个用例中,我将所有路由信息都保存在一个 json 文件中,我想读取该文件并相应地创建路由。

例如,

如果我在我的 json 配置文件中声明了这样的路由

{
  "config": [
    {
      "routeSrcSystem": "System1",
      "routes": [
        {
          "fromRoute": {
            "type": "default",
            "typeValue": "direct:CMStart"
            },  
          "toRoute": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System1/inboundMessage"
            }
        }
      ]
    }
  ]
}

然后我可以动态创建如下路线。但在这里,虽然它是动态的,但路由定义不是动态的,因为我使用了一个“from”和一个“to”定义,但是这个定义的参数我是动态传递的。

public class GenerateRouter extends RouteBuilder {

        private RoutesMetadata routesMetadata;

        public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
            super(context);
            this.routesMetadata=routesMetadata;
        }

        @Override
        public void configure() throws Exception {
            from(routesMetadata.getFromRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue());
        }
    }

但我想动态地进行路由定义。例如,我有这样的路由配置,

{
  "config": [
    {
      "routeSrcSystem": "System1",
      "routes": [
        {
          "fromRoute": {
            "type": "default",
            "typeValue": "direct:CMStart"
            },  
          "toRoute1": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System1/inboundMessage"
            }
         "toRoute2": {
            "type": "http"
            "typeMethod": "POST",
            "typeContent": "application/json",
            "typeValue": "http://localhost:8080/v1/System2/inboundMessage"
            }
        }
      ]
    }
  ]
}

然后在我的路由定义中,我需要动态添加一个“to”定义。它只是一个例子。它可能更具活力。例如,可以更改配置以引入“进程”或“bean”或“类”定义。所以根据配置,我们需要决定要创建多少个“to”以及要创建多少个“process”等等。我可能需要在一些验证等之后调用下一个休息端点,有时我需要调用 kafka 将消息放入队列。我确实看到了一个在列表中列出所有路由并执行它的选项,但我认为我们需要在调用下一个端点之前灵活地添加进程或类定义,这必须基于配置。

public class GenerateRouter extends RouteBuilder {

        private RoutesMetadata routesMetadata;

        public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
            super(context);
            this.routesMetadata=routesMetadata;
        }

        @Override
        public void configure() throws Exception {
            from(routesMetadata.getFromRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue())
            .setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
            .setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
            .to(routesMetadata.getToRoute().getTypeValue());
        }
    }

我看到了一些信息,其中路由定义本身可以动态定义,我正在研究它。但同时我想在这里发布这个以获得专家的意见。另外,请建议我是否以正确的方式使用骆驼?因为在我的用例中,我正在考虑添加“to”定义,根据配置文件动态传递类名,以便应用程序开发人员可以在交付到目标之前动态地在此类中执行转换、丰富或操作的逻辑系统。如果我们有更好的方法,请告诉我。另外,让我知道 XML 的做法是好方法还是以 json 格式定义自己的配置文件是创建动态路由的好方法。

我打算读取 json 文件并动态地创建一个作为字符串的路由器定义。但我需要将此字符串加载为上下文中的定义。我想我错过了这部分。

.to("class:com.xxx.camel.layoutTransform?method=layout()")

如果我们在 xml 文件中提供所有这些配置,并且如果 camel 支持使用该文件自动创建路由定义,那么我们也可以考虑这个选项。

以下是从另一个来源使用 XML 文件创建路由器定义的方法之一。在 XML 中,我们定义了路由器信息,并将此 xml 视为字符串,并将此字符串转换为路由器定义对象,最后添加到上下文中。

<routes
  xmlns=\"http://camel.apache.org/schema/spring\">
  <route>
      <from uri='direct:c'/>
      <to uri='mock:d'/>
  </route>
</routes>
CamelContext context = new DefaultCamelContext(); 
context.setTracing(true); 
String xmlString = "<routes  xmlns=\"http://camel.apache.org/schema/spring\"><route><from uri='direct:c'/><to uri='mock:d'/></route></routes>"; 

InputStream is = new ByteArrayInputStream(xmlString.getBytes()); 
RoutesDefinition routes = context.loadRoutesDefinition(is); 
context.addRouteDefinitions(routes.getRoutes()); 

context.start(); 

ProducerTemplate template = null; 
template = context.createProducerTemplate(); 
template.start(); 
template.sendBody("direct:c", "HelloC"); 
Thread.sleep(10000); 
context.stop();

我想使用 java dsl 定义作为字符串来做类似的概念。

例如,如果我有如下字符串,那么可以将其转换为路由器定义吗?

String dslString = "from("direct:starting").to("seda:end")";

这是我的用例。有时,我们想调用如下 2 个 http 服务

from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2")

有时我们可能需要调用 3 个服务,如下所示

from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2").to("http://localhost:8080/service3")

有时我们需要在调用 service2 之前进行转换,如下所示。

from("direct:start").to(http://localhost:8080/service1).to("class:com.xxx.yyy").to("http://localhost:8080/service2").to("http://localhost:8080/service3")

在偶数驱动架构中,我们必须为每种事件类型定义一组路由。所以想法是,如果我们在表中为每种事件类型定义这些路由,那么在服务启动时,所有路由都将在上下文中加载并启动。我能够以 XML DSL 方式做同样的事情,但尝试在 java DSL 中做同样的事情。

提前致谢!

【问题讨论】:

    标签: spring-boot apache-camel spring-camel camel-http


    【解决方案1】:

    Camel 支持以特定的基于 XML 的格式定义有关路线的所有详细信息。 This page 具有指向该(和其他)DSL 的链接。

    您当然可以提出自己的 DSL 并动态构建路由,但如果您想支持完整的 Camel DSL 将支持的所有内容,那么这将是很多工作。无论您的用例如何,我都怀疑这不是正确的解决方案。

    如果您的路线有某些模式,您可以创建由某些配置驱动的相当动态的 Camel 路线构建器。具体来说,假设您有许多遵循非常相似模式的用例......比如说,来自文件夹中文件的消费者数据,从(比如说)10-15 个转换的菜单中进行一些转换,然后发送输出到多个队列之一。

    由于您有各种可能的组合,因此在文件等中配置这些详细信息然后构建一些路由可能是有意义的。这种权衡与任何其他地方没有什么不同,您必须决定是只编写您想要的 10 件事更清晰,还是让一些更复杂但通用的东西更清晰。

    本质上,您仍将创建 DSL 或排序,但更接近您的用例。

    【讨论】:

    • 感谢您的快速回复!。我找到了一种使用 XML 文件动态创建路由器定义的方法,但我想使用 java DSL 方式来做同样的事情。我已在我的帖子中更新了此信息以获取更多信息
    • 我完全同意 Darius X. 所说的。 OP 正在为 Camel 大致实现一个 JSON DSL,很可能会导致 Inner-platform effect
    • @ShellDragon,谢谢您的建议!.. 如果我的路由信息​​以 DSL 格式定义但保存在字符串变量中,我仍在搜索动态加载路由定义,因为我想做所有的定义都以 DSL 方式而不是 XML 方式。我的问题是,如果我有如下字符串,我可以加载为路由定义吗? String dslString = "from(\"direct:starting\").to(\"seda:end\")";提前致谢!
    • 所以,James... 你是说你想编写 DSL,就像你用 Java 编写 DSL 一样,但是你想把它保存到你读入的某个文件中。本质上。 ..就像在运行时编译的动态 Java 代码?
    • 嗨,Darius - 再次感谢您的回复!.. 是的,您是正确的。我们可以选择吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 2022-11-12
    • 1970-01-01
    • 2014-10-26
    • 2023-04-11
    • 2019-09-09
    相关资源
    最近更新 更多