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

 属性占位符


Camel 广泛支持属性占位符,几乎可以在 Camel 路由、端点、DSL、路由配置、Bean 集成和其他地方使用。


属性占位符用于定义占位符而不是实际值。这一点非常重要,因为您希望应用程序可以进行外部配置,例如网络地址、端口号、身份验证凭据、登录令牌和一般配置的值。

 属性组件


Camel 核心提供了开箱即用的属性,负责处理和解析属性占位符。


请参阅属性文档,了解如何配置 Camel 以知道从哪个位置(a)加载属性。


属性占位符语法


通过使用以下语法在属性占位符中指定键名,可以获取 Camel 属性的值: {{key}}

 例如

{{file.uri}}


其中 file.uri 是属性键。


通过在 URI 字符串定义中嵌入一个或多个占位符,属性占位符可用于指定端点 URI 的部分或全部内容。


使用带有默认值的属性占位符


您可以指定一个默认值,以便在不存在具有该键的属性时使用,默认值为冒号后的文本:

{{file.url:/some/path}}


在这种情况下,默认值为 /some/path 。.


使用可选属性占位符


Camel 精心设计的属性占位符功能支持可选占位符,在键名中使用 ? (问号)作为前缀定义占位符。(问号)作为键名的前缀来定义,如图所示:

{{?myBufferSize}}


如果键的值存在,则使用该值,但如果键不存在,Camel 会理解这一点,例如在端点中使用时:

file:foo?bufferSize={{?myBufferSize}}


如果存在占位符, bufferSize 选项将只在端点中配置。否则,将不会在端点上设置该选项,这意味着端点将被重构为:

file:foo


这样, bufferSize 选项就完全不需要指定,Camel 就可以使用 bufferSize 的标准默认值(如果存在的话)。


反转布尔值


如果属性占位符是一个布尔值,则可以通过在键中使用 ! 作为前缀来否定(反转)该值。

integration.ftpEnabled=true
from("ftp:....").autoStartup("{{integration.ftpEnabled}}")
    .to("kafka:cheese")

from("jms:....").autoStartup("{{!integration.ftpEnabled}}")
    .to("kafka:cheese")


在上述示例中,FTP 路由或 JMS 路由只应启动。因此,如果启用了 FTP,则应禁用 JMS,反之亦然。我们可以使用 !integration.ftpEnabled 作为关键字,否定 JMS 路由中的 autoStartup


使用属性占位符


在端点 URI 中使用属性占位符时,应使用本示例中所示的 {{key}} 语法:

cool.end = mock:result
where = cheese


而在 Java DSL 中:

from("direct:start")
    .to("{{cool.end}}");


以及 XML DSL:

<route>
  <from uri="direct:start"/>
  <to uri="{{cool.end}}"/>
</route>


属性占位符也可以只是端点 URI 中的一个部分。常见的使用情况是为端点选项(如文件端点中写缓冲区的大小)使用占位符:

buf = 8192
from("direct:start")
    .to("file:outbox?bufferSize={{buf}}");


以及 XML DSL:

<route>
  <from uri="direct:start"/>
  <to uri="file:outbox?bufferSize={{buf}}"/>
</route>


不过,占位符可以是任何地方的名称,因此也可以是模拟端点的名称

from("direct:start")
    .to("mock:{{where}}");


在上面的示例中,模拟端点已被硬编码为以 mock: 开始,而 where 占位符的值为 cheese ,因此解析后的 uri 变成了 mock:cheesewhere 占位符的值为 cheese ,因此解析后的 uri 变成了 mock:cheese 。.


引用其他属性的属性占位符(嵌套占位符)


您还可以设置相互参照的属性,例如

cool.foo=result
cool.concat=mock:{{cool.foo}}


请注意 cool.concat 是如何指向另一个属性的。


以及 XML 中的路线:

<route>
  <from uri="direct:start"/>
  <to uri="{{cool.concat}}"/>
</route>


关闭嵌套占位符


如果占位符值包含干扰属性占位符语法 {{}} 的数据(如 JSon 数据),则可以通过在键名中使用 ?nested=false 来显式关闭嵌套占位符,如图所示(如 JSon 数据),则可以通过键名中的 ?nested=false 明确关闭嵌套占位符,如图所示:

<route>
  <from uri="direct:start"/>
  <to uri="elasticsearch:foo?query={{myQuery?nested=false}}"/>
</route>


在上面的示例中,myQuery 占位符的占位符值如下

{"query":{"match_all":{}}}


请注意 json 查询是如何以 }} 结尾的,这与 Camel 属性占位符语法有冲突。


也可以在 "属性 "组件上全局关闭嵌套占位符,例如

CamelContext context = ...
context.getPropertiesComponent().setNestedPlaceholder(false);


转义属性占位符


如果第三方库(例如 ElasticSearch 中 {"query":{"match_all":{}}} 类型的查询)使用双大括号,则属性占位符可能会出现问题。.


要解决这个问题,可以用反斜杠字符转义双引号,例如 \{{ property-name \}} .这样,它就不会被解释为属性占位符来解析,而会被解析为 {{ property-name }} 。.


如果由于某种原因,双引号前的反斜杠字符不能被解释为转义字符,可以在其前面添加另一个反斜杠来转义,这样它就会被视为反斜杠。


多次使用属性占位符


当然,您也可以多次使用占位符:

cool.start=direct:start
cool.showid=true
cool.result=result


在这条路径中,我们使用了两次 cool.start

from("{{cool.start}}")
    .to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}")
    .to("mock:{{cool.result}}");


使用生产者模板的属性占位符


例如,您还可以在使用 ProducerTemplate 时使用属性占位符:

template.sendBody("{{cool.start}}", "Hello World");


使用消费者模板的属性占位符


在使用 ConsumerTemplate 时也可以这样做,例如

Object body = template.receiveBody("{{cool.start}}");


从 Java 代码中解析属性占位符


如果您需要从 Java 代码中解析属性占位符,那么 Camel 有两个 API 可用于此目的:


  • 您可以使用 PropertiesComponent 上的方法 resolveProperty 来解析 Java 代码中的单个属性。


  • 使用 CamelContext 上的方法 resolvePropertyPlaceholders 来解析字符串中的(一个或多个)属性占位符。


例如,要解析键值为 foo 的占位符,可以这样做:

Optional<String> prop = camelContext.getPropertiesComponent().resolveProperty("foo");
if (prop.isPresent()) {
    String value = prop.get();
    ....
}


此 API 用于查找单个属性,并返回 java.util.Optional 类型。


CamelContext 的另一个 API 能够解析多个占位符,并从输入字符串中插入占位符。让我们举例说明一下:

String msg = camelContext.resolvePropertyPlaceholders("{{greeting}} Camel user, Camel is {{cool}} dont you think?");


输入字符串是一个文本语句,其中有两个将被解析的占位符,例如

greeting = Hi
cool = awesome


将解决:

Hi Camel user, Camel is awesome dont you think?


在 spring xml 文件中为任何类型的属性使用属性占位符


以前,只有 XML DSL 中的 xs:string 类型属性才支持占位符。例如,超时属性通常属于 xs:int 类型,因此无法将字符串值设置为占位符键。现在可以使用特殊的占位符命名空间来实现这一点。


在下面的示例中,我们为命名空间 http://camel.apache.org/schema/placeholder 使用 prop 前缀。.现在,我们可以使用 prop: 作为前缀,在 Spring XML 文件中配置任何类型的 XML 属性。


在下面的示例中,我们希望在组播 EIP 中使用 stopOnException 选项的占位符。 stopOnExceptionxs:boolean 类型,因此我们不能将其配置为:

<multicast stopOnException="{{stop}}">
   ...
</multicast>


相反,我们必须使用 prop: 命名空间,因此必须在 XML 文件顶部的 <beans> 标记中添加该命名空间。


如下图所示,要配置该选项,我们必须使用 prop:optionName

<multicast prop:stopOnException="stop">
  ...
</multicast>


完整示例如下:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:prop="http://camel.apache.org/schema/placeholder"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
           http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <bean id="damn" class="java.lang.IllegalArgumentException">
        <constructor-arg index="0" value="Damn"/>
    </bean>

    <camelContext xmlns="http://camel.apache.org/schema/spring">
        <propertyPlaceholder id="properties" location="classpath:myprop.properties"/>
        <route>
            <from uri="direct:start"/>
            <!-- use prop namespace, to define a property placeholder, which maps to option stopOnException={{stop}} -->
            <multicast prop:stopOnException="stop">
                <to uri="mock:a"/>
                <throwException ref="damn"/>
                <to uri="mock:b"/>
            </multicast>
        </route>
    </camelContext>
</beans>


在属性文件中,我们将值定义为

stop = true


将 camel 属性占位符与 spring xml 文件桥接起来


如果您使用的是 Spring Boot,则不适用。这只适用于使用 Spring XML 文件的传统 Camel 和 Spring 应用程序。


Spring 框架不允许 Apache Camel 等第三方框架无缝挂钩 Spring 属性占位符机制。不过,您可以通过声明一个 org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer 类型的 Spring Bean 来连接 Spring 和 Camel。的 Spring Bean,它是 Spring org.springframework.beans.factory.config.PropertyPlaceholderConfigurer 类型。


要在 Spring 和 Camel 之间架起桥梁,必须定义一个单独的 Bean,如下图所示:

<!-- bridge spring property placeholder with Camel -->
<!-- you must NOT use the <context:property-placeholder at the same time, only this bridge bean -->
<bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
  <property name="location" value="classpath:org/apache/camel/component/properties/cheese.properties"/>
</bean>


您不能同时使用弹簧 <context:property-placeholder> 命名空间;这是不可能的。


声明此 Bean 后,您可以在 <camelContext> 标记中使用 Spring 样式和 Camel 样式定义属性占位符,如下所示:

<!-- a bean that uses Spring property placeholder -->
<!-- the ${hi} is a spring property placeholder -->
<bean id="hello" class="org.apache.camel.component.properties.HelloBean">
  <property name="greeting" value="${hi}"/>
</bean>

<camelContext xmlns="http://camel.apache.org/schema/spring">
  <!-- in this route we use Camels property placeholder {{ }} style -->
  <route>
    <from uri="direct:{{cool.bar}}"/>
    <bean ref="hello"/>
    <to uri="{{cool.end}}"/>
  </route>
</camelContext>


请注意,hello Bean 使用了纯 Spring 属性占位符 ${} 符号。而在 Camel 路由中,我们使用了带有 {{key}} 的 Camel 占位符符号。.


使用属性占位符函数


属性 "组件包括以下开箱即用的功能:


  • env - 从操作系统环境变量中查找属性的函数


  • sys - 从 Java JVM 系统属性中查找属性的函数


  • bean - 用于从 bean 方法的返回值中查找属性的函数(需要 camel-bean JAR)


  • service - 使用服务命名习语从操作系统环境变量中查找属性的函数


  • service.name - 使用服务命名习惯从操作系统环境变量中查找属性的函数,仅返回主机名部分


  • service.port - 使用服务命名习惯从操作系统环境变量中查找属性的函数,仅返回端口部分


这些函数的目的是方便从环境中查找值,如下例所示:

<camelContext>
    <route>
        <from uri="direct:start"/>
        <to uri="{{env:SOMENAME}}"/>
        <to uri="{{sys:MyJvmPropertyName}}"/>
    </route>
</camelContext>


您也可以使用默认值,因此如果属性不存在,您可以定义一个默认值,如下图所示,默认值为 log:foolog:bar 值。

<camelContext>
    <route>
        <from uri="direct:start"/>
        <to uri="{{env:SOMENAME:log:foo}}"/>
        <to uri="{{sys:MyJvmPropertyName:log:bar}}"/>
    </route>
</camelContext>


服务函数用于查找使用操作系统环境变量定义的服务,使用服务命名习惯用语 hostname : port 来引用服务位置。

  •  服务主机名称

  •  服务端口名称


换句话说,服务使用 _SERVICE_HOST_SERVICE_PORT 作为前缀。因此,如果服务名为 FOO,那么操作系统环境变量应设置为

export $FOO_SERVICE_HOST=myserver
export $FOO_SERVICE_PORT=8888


例如,如果 FOO 服务是一个远程 HTTP 服务,那么我们可以在 Camel 端点 uri 中引用该服务,并使用 HTTP 组件进行 HTTP 调用:

<camelContext>
    <route>
        <from uri="direct:start"/>
        <to uri="http://{{service:FOO}}/myapp"/>
    </route>
</camelContext>


如果服务尚未定义,我们可以使用默认值,例如调用 localhost 上的服务,也许是为了进行单元测试。

<camelContext>
<route>
    <from uri="direct:start"/>
    <to uri="http://{{service:FOO:localhost:8080}}/myapp"/>
</route>
</camelContext>


bean 函数(需要在类路径上有 camel-bean JAR)用于从 bean 方法的返回值中查找属性。


假设我们注册了一个名为 "foo "的 bean,它有一个名为 "bar "的方法,可以返回一个目录名,那么我们就可以在 camel 端点 url 中引用 bean 的方法,并使用文件组件来轮询一个目录:

<camelContext>
<route>
    <from uri="file:{{bean:foo.bar}}"/>
    <to uri="direct:result"/>
</route>
</camelContext>

该方法必须是无参数公共方法(即无参数),并返回一个值,如字符串、布尔值或 int 值。


使用 kubernetes 属性占位符函数


camel-kubernetes 组件包括以下功能:


  • configmap - 用于从 Kubernetes 配置表中查找属性的函数。


  • secret - 从 Kubernetes Secrets 查找属性的函数。


这两个函数的语法都是

configmap:name/key[:defaultValue]


默认值是可选的,例如,以下代码将查找 myKey ,如果没有这样的 configmap,则查找失败。

configmap:mymap/mykey


在本例中,由于提供了默认值,因此不会失败:

configmap:mymap/mykey:123


在使用 Kubernetes 属性占位符函数之前,需要用以下两种方法之一(或两种)对其进行配置


  • path - 必须挂载到运行 pod 的挂载路径,以便从本地磁盘加载配置映射或秘密。


  • 一个用于连接 Kubernetes API 服务器的 io.fabric8.kubernetes.client.KubernetesClient 实例。


Camel 将首先使用挂载路径(如果已配置)进行查找,然后回退到使用 KubernetesClient 。.


为配置映射和机密配置挂载路径


挂载路径的配置按给定顺序使用:


  1. 读取键值为 camel.kubernetes-config.mount-path-configmapscamel.kubernetes-config.mount-path-secrets 的配置属性 ..


  2. 使用关键字 camel.k.mount-path.configmapscamel.k.mount-path.secrets 的 JVM 系统属性(与 Camel K 兼容)。(与 Camel K 兼容)。


  3. 使用 OS ENV 变量,键值为 CAMEL_K_MOUNT_PATH_CONFIGMAPSCAMEL_K_MOUNT_PATH_SECRETS (与 Camel K 兼容)。(与 Camel K 兼容)。


例如,若要使用 /etc/camel/resources/ 作为挂载路径,可在 application.properties

camel.kubernetes-config.mount-path-configmaps = /etc/camel/myconfig/
camel.kubernetes-config.mount-path-secrets = /etc/camel/mysecrets/


配置 kubernetes 客户端


如果运行中的应用程序中存在一个客户端实例(通过注册表查找),Camel 将自动连接 KubernetesClient 。否则,将创建一个新的 KubernetesClient 。客户端可以通过以下两种方式进行配置


  • 使用 camel.kubernetes-config.client. 属性(示例见下文)


  • 通过操作系统环境变量、读取 ~./kube/config 配置和服务账户令牌文件的组合,尝试自动配置。更多详情,请参阅 https://github.com/fabric8io/kubernetes-client 文档。


只有在从本地计算机连接到远程 Kubernetes 集群时,才可能需要显式配置 KubernetesClient ,此时可以指定各种选项,如 masterUrl 和 oauthToken,如图所示:

camel.kubernetes-config.client.masterUrl = https://127.0.0.1:50179/
camel.kubernetes-config.client.oauthToken = eyJhbGciOiJSUzI1NiIsImtpZCI...


KubernetesClient 有许多选项,请参阅 https://github.com/fabric8io/kubernetes-client 文档。


如果只使用挂载路径,那么禁用 KubernetesClient 是个不错的做法,可以将 enabled 设置为 false,如图所示:

camel.kubernetes-config.client-enabled = false


在现有的 Kubernetes 集群中运行 Camel 应用程序时,通常不需要对 KubernetesClient 进行显式配置,可以使用默认设置。


如果使用骆驼 Quarkus,建议使用其 https://quarkus.io/guides/kubernetes-config,该网站会自动预配置 KubernetesClient ,然后骆驼会重复使用。


在 Kubernetes 中使用 configmap


给定 Kubernetes 中名为 myconfig 的配置映射有两个条目:

drink = beer
first = Carlsberg


然后就可以在 Camel 路由中使用这些值,例如

<camelContext>
  <route>
    <from uri="direct:start"/>
    <log message="What {{configmap:myconfig/drink}} do you want?"/>
    <log message="I want {{configmap:myconfig/first}}"/>
  </route>
</camelContext>


您还可以提供一个默认值,以防某个键不存在:

    <log message="I want {{configmap:myconfig/second:Heineken}}"/>


在 Kubernetes 中使用秘密


Camel 从 Kubernetes API 服务器读取配置映射。在集群上启用 RBAC 时,用于运行应用程序的 ServiceAccount 需要有适当的访问权限。


名为 mydb 的秘密可能包含连接数据库的用户名和密码,例如

myhost = killroy
myport = 5555
myuser = scott
mypass = tiger


这可以在 Camel 中与 Postrgres Sink Kamelet 等一起使用:

<camelContext>
  <route>
    <from uri="direct:rome"/>
    <setBody>
      <constant>{ "username":"oscerd", "city":"Rome"}</constant>
    </setBody>
    <to uri="kamelet:postgresql-sink?serverName={{secret:mydb/myhost}}
             &amp;serverPort={{secret:mydb/myport}}
             &amp;username={{secret:mydb/myuser}}
             &amp;password={{secret:mydb/mypass}}
             &amp;databaseName=cities
             &amp;query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/>
  </route>
</camelContext>


postgres-sink Kamelet 也可以在 application.properties 中配置,从而减少上述路由中的配置:

camel.component.kamelet.postgresql-sink.databaseName={{secret:mydb/myhost}}
camel.component.kamelet.postgresql-sink.serverPort={{secret:mydb/myport}}
camel.component.kamelet.postgresql-sink.username={{secret:mydb/myuser}}
camel.component.kamelet.postgresql-sink.password={{secret:mydb/mypass}}


这就把路线缩短为

<camelContext>
  <route>
    <from uri="direct:rome"/>
    <setBody>
      <constant>{ "username":"oscerd", "city":"Rome"}</constant>
    </setBody>
    <to uri="kamelet:postgresql-sink?databaseName=cities
             &amp;query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/>
  </route>
</camelContext>


在本地模式下使用 configmap 或秘钥


在开发过程中,你可能希望在本地模式下运行,在这种模式下,你不需要访问 Kubernetes 集群就能查找配置图。在本地模式下,Camel 会从本地属性中查找配置映射键,例如


例如上面使用 postgresql kamelet 的例子,就是使用秘密配置的:

camel.component.kamelet.postgresql-sink.databaseName={{secret:mydb/myhost}}
camel.component.kamelet.postgresql-sink.serverPort={{secret:mydb/myport}}
camel.component.kamelet.postgresql-sink.username={{secret:mydb/myuser}}
camel.component.kamelet.postgresql-sink.password={{secret:mydb/mypass}}


现在,假设我们想使用本地 Postrgres 数据库,那么我们可以打开本地模式,并在同一属性文件中指定凭据:

camel.kubernetes-config.local-mode = true
mydb/myhost=localhost
mydb/myport=1234
mydb/myuser=scott
mydb/mypass=tiger

注意密钥的前缀是秘密名称和斜线,例如 name/key 。.这样就可以轻松地从 configmap/secret 的实际使用中复制/粘贴到 application.properties 文件中。


使用自定义属性占位符函数


属性组件允许插入第三方函数,这些函数可在解析属性占位符时使用。这些函数可以执行自定义逻辑来解析占位符,例如在数据库中查找、进行自定义计算等。函数名称将成为占位符中使用的前缀。


下面的路由示例最能说明这一点,我们使用 beer 作为前缀:

<route>
    <from uri="direct:start"/>
    <to uri="{{beer:FOO}}"/>
    <to uri="{{beer:BAR}}"/>
</route>


如下图所示,该函数的实现只有两个方法:

@org.apache.camel.spi.annotations.PropertiesFunction("beer")
public class MyBeerFunction implements PropertiesFunction {

    @Override
    public String getName() {
        return "beer";
    }

    @Override
    public String apply(String remainder) {
        return "mock:" + remainder.toLowerCase();
    }
}


函数必须实现 org.apache.camel.spi.PropertiesFunction 接口。方法 getName 是函数(啤酒)的名称。而 apply 方法是我们实现自定义逻辑的地方。由于示例代码来自单元测试,因此它只是返回一个值,用于引用模拟端点。


您还需要将 camel-component-maven-plugin 作为构建组件的一部分,这样才能确保该自定义属性函数生成了必要的源代码,使 Camel 能够自动发现该函数。


如果自定义属性函数需要启动和关闭的逻辑,则可扩展 ServiceSupport 并在 doStartdoStop 方法中加入该逻辑。

有关示例,请参阅 camel-base64 组件。


使用第三方财产来源


属性组件允许插入第三方资源,通过来自 camel-api 的 PropertySource API 加载和查找属性。API 从 camel-api 加载和查询属性。


常规 PropertySource 将按需查找属性,例如从数据库或 HashiCorp Vault 等后台来源查找值。


PropertySource 可以定义支持一次性从源代码(例如文件系统)加载所有属性(通过实现 LoadablePropertiesSource )。这样,Camel 属性组件就可以在启动时一次性加载这些属性。


例如, camel-microprofile-config 组件就是通过这种方式实现的。当 Camel 启动时,第三方 PropertySource 可以自动从 classpath 中被发现。具体方法是在文件 META-INF/services/org/apache/camel/property-source-factory 中加入 PropertySource 实现的全限定类名。


请参阅 MicroProfile Config 组件的示例。


您还可以通过 Java API 注册第三方属性源:

PropertiesComponent pc = context.getPropertiesComponent();
pc.addPropertiesSource(myPropertySource);