这是用户在 2024-3-28 22:09 为 https://camel.apache.org/manual/property-binding.html 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

Property binding in Camel
在 Camel 中的属性绑定

Camel supports binding property values (key=value) in many places such as configuration of Camel components, endpoints, EIPs, routes, and Camel bootstrap configuration.
Camel 在许多地方支持绑定属性值(键=值),例如 Camel 组件、端点、EIP、路由和 Camel 引导配置的配置。

Together with property placeholders, property placeholder functions, then there is plenty of power, but also something that takes a little learning to master.
一起使用属性占位符和属性占位符函数,就会有很大的能力,但也需要一些学习才能掌握。

Property binding features
属性绑定功能

The core of Camels property binding is implemented in PropertyBindingSupport.java which is used internally in Camel, and as well can be used by Camel component developers.
Camel 属性绑定的核心是在{{0}}中实现的,它在 Camel 内部使用,并且也可以被 Camel 组件开发者使用。

The PropertyBindingSupport class supports binding String valued properties to an instance which uses a set of conventions:
{{0}}类支持将字符串类型的属性绑定到使用一组约定的实例上

  • property placeholders - Keys and values using Camels property placeholder will be resolved.
    属性占位符 - 使用 Camels 属性占位符的键和值将被解析。

  • nested - Properties can be nested using the dot syntax (OGNL and builder pattern using with as prefix), eg foo.bar=123.
    嵌套 - 使用点语法(OGNL 和构建器模式使用 with 作为前缀)可以嵌套属性,例如{{0}}。

  • map - Properties can lookup in Map’s using map syntax, eg foo[bar] where foo is the name of the property that is a Map instance, and bar is the name of the key.
    map - 使用地图语法可以在地图中查找属性,例如{{0}},其中 foo 是地图实例的属性名称,bar 是键的名称。

  • list - Properties can refer or add to in List’s using list syntax, eg foo[0] where foo is the name of the property that is a List instance, and 0 is the index. To refer to the last element, then use last as key.
    列表 - 属性可以使用列表语法引用或添加到列表中,例如{{0}},其中 foo 是一个列表实例的属性名称,0 是索引。要引用最后一个元素,请使用{{1}}作为键。

  • reference by property placeholder id - Values can refer to a property placeholder key with #property:myKey
    引用属性占位符 ID - 值可以使用{{0}}引用属性占位符键

  • reference by bean id - Values can refer to other beans in the registry by prefixing with # or #bean: eg #myBean or #bean:myBean. It is recommended to favour using #bean: syntax to make it obvious it’s a bean reference.
    按 bean id 引用 - 值可以通过在前面加上{{0}}或{{1}}来引用注册表中的其他 bean,例如{{2}}或{{3}}。建议使用{{4}}语法,以明确表示它是一个 bean 引用。

  • reference by type - Values can refer to singleton beans by their type in the registry by prefixing with #type: syntax, eg #type:com.foo.MyClassType.
    按类型引用 - 值可以通过在注册表中使用{{0}}语法前缀来引用单例 bean,例如{{1}}。

  • autowire by type - Values can refer to singleton beans by auto wiring by setting the value to #autowired.
    按类型自动装配 - 值可以通过将值设置为{{0}}来自动装配单例 bean。

  • reference new class - Values can refer to creating new beans by their class name by prefixing with #class, eg #class:com.foo.MyClassType. The class is created using a default no-arg constructor, however if you need to create the instance via a factory method then you specify the method as shown: #class:com.foo.MyClassType#myFactoryMethod. And if the factory method requires parameters they can be specified as follows: #class:com.foo.MyClassType#myFactoryMethod('Hello World', 5, true). Or if you need to create the instance via constructor parameters then you can specify the parameters as shown: #class:com.foo.MyClass('Hello World', 5, true). If the factory method is on another bean or class, then you must specify this as shown: #class:com.foo.MyClassType#com.foo.MyFactory:myFactoryMethod. Where com.foo.MyFactory either refers to a FQN classname, or can refer to an existing bean by id, such as: #class:com.foo.MyClassType#myFactoryBean:myFactoryMethod.
    引用新类 - 值可以通过在类名前加上{{0}}来引用创建新的 bean,例如{{1}}。该类使用默认的无参构造函数创建,但如果您需要通过工厂方法创建实例,则可以按如下所示指定方法:{{2}}。如果工厂方法需要参数,则可以按如下所示指定参数:{{3}}。或者,如果您需要通过构造函数参数创建实例,则可以按如下所示指定参数:{{4}}。如果工厂方法在另一个 bean 或类上,则必须按如下所示指定:{{5}}。其中{{6}}可以是完全限定类名,也可以是现有 bean 的 id,例如:{{7}}。

  • valueAs(type):value - To declare that the value should be converted to the given type, such as #valueAs(int):123 which indicates that the value 123 should be converted to an integer.
    valueAs(type):value - 声明该值应转换为给定类型,例如{{0}}表示值 123 应转换为整数。

  • ignore case - Whether to ignore case for property keys (will ignore by default)
    忽略大小写 - 是否忽略属性键的大小写(默认情况下会忽略)

Property binding basics 属性绑定基础

Do not get overwhelmed by the set of features and what they really do.
不要被功能集合和它们的实际作用所压倒。

At the basics the property binding are used for setting values on Java objects from string values (key=value).
基本上,属性绑定用于从字符串值(键=值)设置 Java 对象上的值。

For example to set brokers on the Kafka component you can do:
例如,要在 Kafka 组件上设置代理,您可以执行以下操作:

camel.component.kafka.brokers = mykafka1,mykafka2

This will essentially be equivalent to configuring Kafka component in regular Java code via setters:
这基本上相当于通过设置器在常规 Java 代码中配置 Kafka 组件

KafkaComponent kafka = ...
kafka.setBrokers("mykafka1,mykafka2");
For configuring Camel components in Java code, there is also Component DSL.
用于在 Java 代码中配置 Camel 组件,还有组件 DSL。

The configuration of Camel components, endpoints, routes etc can often require more flexibility and therefore the property binding has many features to bind by looking up existing objects by id, or anonymously by their type, and as well to walk down an object graph to bind nested parameters.
Camel 组件、端点、路由等的配置通常需要更多的灵活性,因此属性绑定具有许多功能,可以通过查找现有对象的 id 或匿名方式绑定,还可以沿着对象图遍历以绑定嵌套参数。

Using PropertyBindingSupport in Java
使用 PropertyBindingSupport 在 Java 中

Although PropertyBindingSupport is not primary intended for end users to use, but nevertheless its possible to use, and also you may get a better understanding of this feature by seeing how this class is used with pure Java.
尽管{{0}}并非主要用于最终用户使用,但仍然可以使用,并且通过查看如何使用纯 Java 来使用此类,您可能会更好地理解此功能。

Suppose we have the following two POJOs Foo.java and Bar.java:
假设我们有以下两个 POJOs {{0}} 和 {{1}}:

public class Foo {
    private String name;
    private Bar bar = new Bar();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Bar getBar() {
        return bar;
    }

    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

public class Bar {
    private int age;
    private boolean rider;

    public int getAge() {
        return age;
    }

    public boolean isRider() {
        return rider;
    }

    // this has no setter but only builders and mix the builders with both styles

    public Bar withAge(int age) {
        this.age = age;
        return this;
    }

    public Bar withRider(boolean rider) {
        this.rider = rider;
        return this;
    }
}

Then we can use PropertyBindingSupport to bind properties to these POJOs:
然后我们可以使用{{0}}将属性绑定到这些 POJOs 上:

Foo foo = new Foo();

Map<String, Object> prop = new HashMap<>();
prop.put("name", "James");
prop.put("bar.age", "33");
prop.put("bar.rider", "true");

PropertyBindingSupport.bindProperties(context, foo, prop);

This will then set the POJOs to have the following values:
这将设置 POJOs 具有以下值:

Foo.name = James
Foo.Bar.age = 33
Foo.Bar.rider = true

Instead of providing a map with all the parameters then a single parameter can also be set using builder style as shown:
可以使用构建器样式来设置单个参数,而不是提供包含所有参数的地图

Foo foo = new Foo();

PropertyBindingSupport.build().bind(context, foo, "name", "James");
PropertyBindingSupport.build().bind(context, foo, "bar.age", "33");
PropertyBindingSupport.build().bind(context, foo, "bar.rider", "true");

Which is more common to do as follows:
以下哪种做法更常见:

Foo foo = new Foo();

PropertyBindingSupport.build().withCamelContext(context).withTarget(foo)
    .withProperty("name", "James");
    .withProperty("bar.age", "33");
    .withProperty("bar.rider", "true")
    .bind();

In the example above then we are setting nested values on foo via bar.age and bar.rider. This is possible because Foo class has a getBar method that returns the Bar instance to use:
在上面的示例中,我们通过{{0}}和{{1}}在 foo 上设置了嵌套值。这是可能的,因为 Foo 类有一个{{2}}方法,返回要使用的{{3}}实例。

    private Bar bar = new Bar();

    public Bar getBar() {
        return bar;
    }

It’s a common practice for POJO classes to not create nested instances, but instead on demand. So suppose private Bar bar = new Bar(); was not present in the Foo class. In this situation then Camel will automatic create a new instance of Bar using its default no-arg constructor. For more advanced use-cases then you can specify how the Bar instance should be created, such as via a factory method, or pass in constructor parameters.
POJO 类通常不会创建嵌套实例,而是按需创建。假设 Foo 类中没有{{0}},在这种情况下,Camel 将自动使用其默认的无参构造函数创建一个新的{{1}}实例。对于更高级的用例,您可以指定如何创建 Bar 实例,例如通过工厂方法或传递构造函数参数。

For example suppose Bar has a constructor parameter that accepts a boolean, we can pass that information via #class: as shown:
例如,假设 Bar 有一个接受布尔值的构造函数参数,我们可以通过{{0}}传递该信息,如下所示:

PropertyBindingSupport.build().withCamelContext(context).withTarget(foo)
    .withProperty("name", "James");
    .withProperty("bar", "#class:com.mycompany.Bar(true)")
    .withProperty("bar.age", "33");
    .withProperty("bar.rider", "true")
    .bind();

Using fluent builder class
使用流畅构建器类

When you are in need to configure a bean via fluent builder class, such as the following example:
当您需要通过流畅的构建器类配置一个 bean 时,例如以下示例:

public class MyDriverBuilder {

 private String url;
 private String username;
 private String password;

 public MyDriverBuilder url(String url) {
     this.url = url;
     return this;
 }

 public MyDriverBuilder username(String username) {
     this.username = username;
     return this;
 }

 public MyDriverBuilder password(String password) {
     this.password = password;
     return this;
 }

 public MyDriver build() {
     return new MyDriver(url, username, password);
 }
}

And you want to create an instance of MyDriver via the MyDriverBuilder class, then this can be done as follows:
并且您想通过{{1}}类创建一个{{0}}的实例,那么可以按照以下方式完成:

MyDriver driver = PropertyBindingSupport.build()
  .withCamelContext(context)
  .withTarget(new MyDriverBuilder())
  .withFluentBuilder(true)
  .withProperty("url", "localhost:1234")
  .withProperty("username", "scott")
  .withProperty("password", "tiger")
  .build(MyDriver.class);

Notice how we use the build(MyDriver.class) to build the bean via the target class .withTarget(new MyDriverBuilder()). The build method will by default invoke build as the builder method, but you can specify the name, such as .build(MyDriver.class, "myBuilderMethod");
注意我们如何使用{{0}}通过目标类{{1}}来构建 bean。默认情况下,build 方法将调用{{2}}作为构建器方法,但您可以指定名称,例如{{3}}。

More details 更多细节

Property binding is notably used when running Camel in standalone mode with Camel Main, or using Camel Spring Boot, Camel K, Camel Kafka Connector, or Camel Quarkus. All these runtimes have a similar way of configuring via property bindings such as from application.properties files.
属性绑定在使用 Camel Main 独立模式、Camel Spring Boot、Camel K、Camel Kafka Connector 或 Camel Quarkus 时特别常用。所有这些运行时都有一种类似的配置方式,可以通过属性绑定来配置,例如从{{0}}文件中。

See more at Camel Main
请参阅骆驼主页