属性占位符函数
属性占位符函数
Properties 组件开箱即用地包含以下函数:
env- 用于从操作系统环境变量中查找属性的函数sys- 用于从 Java JVM 系统属性中查找属性的函数bean- 用于从 Bean 方法的返回值中查找属性的函数(需要camel-beanJAR)boolean- 用于判断属性键是否满足某个条件,并返回true或false的函数service- 使用服务命名惯例从操作系统环境变量中查找属性的函数service.name- 使用服务命名惯例从操作系统环境变量中查找属性的函数,仅返回主机名部分service.port- 使用服务命名惯例从操作系统环境变量中查找属性的函数,仅返回端口部分
这些函数旨在方便地从环境中查找值,如下面的示例所示:
- Java
- XML
- YAML
from("direct:start")
.to("{{env:SOMENAME}}")
.to("{{sys:MyJvmPropertyName}}");<route>
<from uri="direct:start"/>
<to uri="{{env:SOMENAME}}"/>
<to uri="{{sys:MyJvmPropertyName}}"/>
</route>- route:
from:
uri: direct:start
steps:
- to:
uri: "{{env:SOMENAME}}"
- to:
uri: "{{sys:MyJvmPropertyName}}"你也可以使用默认值,如果属性不存在,可以按如下方式定义默认值,其中默认值为 log:foo 和 log:bar。
- Java
- XML
- YAML
from("direct:start")
.to("{{env:SOMENAME:log:foo}}")
.to("{{sys:MyJvmPropertyName:log:bar}}");<route>
<from uri="direct:start"/>
<to uri="{{env:SOMENAME:log:foo}}"/>
<to uri="{{sys:MyJvmPropertyName:log:bar}}"/>
</route>- route:
from:
uri: direct:start
steps:
- to:
uri: "{{env:SOMENAME:log:foo}}"
- to:
uri: "{{sys:MyJvmPropertyName:log:bar}}"布尔函数旨在为启用或停用 EIP 选项提供更大的灵活性。
例如,假设我们有一个键为 region、值为 EMEA 的属性:
region = EMEA然后我们可以根据该条件配置 EIP 是否被禁用,方式如下:
- Java
- XML
- YAML
from("direct:start")
.choice().disabled("{{boolean:region == 'EMEA'}}")
.when(simple("${header.RetryAttempts} == null"))
.setProperty("HttpMessageMethod", constant("SET"))
.process("SetOriginalMessageProcessor")
.end();<route>
<from uri="direct:start"/>
<choice disabled="{{boolean:region == 'EMEA'}}">
<when>
<simple>${header.RetryAttempts} == null</simple>
<setProperty name="HttpMessageMethod">
<constant>SET</constant>
</setProperty>
<process ref="SetOriginalMessageProcessor"/>
</when>
</choice>
</route>- route:
from:
uri: direct:start
steps:
- choice:
disabled: "{{boolean:region == 'EMEA'}}"
when:
- expression:
simple:
expression: "${header.RetryAttempts} == null"
steps:
- setProperty:
name: "HttpMessageMethod"
expression:
constant: "SET"
- process:
ref: "SetOriginalMessageProcessor"属性占位符也可在 application.properties 文件中使用,同样支持如 ENV 之类的函数,示例如下:
# server name read from ENV and fallback to use localhost as default value
myserver = {{env:MY_SERVER_NAME:localhost}}bool 函数使用 Simple 语言,该语言提供了许多用于构建条件的函数和运算符。 |
|---|
service 函数用于查找通过操作系统环境变量定义的服务,它采用服务命名惯例,通过 hostname : port 来引用服务地址:
- NAME_SERVICE_HOST
- NAME_SERVICE_PORT
也就是说,服务使用 _SERVICE_HOST 和 _SERVICE_PORT 作为前缀。因此,如果服务名为 FOO,则应将操作系统环境变量设置为:
export $FOO_SERVICE_HOST=myserver
export $FOO_SERVICE_PORT=8888例如,如果 FOO 服务是一个远程 HTTP 服务,那么我们可以在 Camel 端点 URI 中引用该服务,并使用 HTTP 组件发起 HTTP 调用:
- Java
- XML
- YAML
from("direct:start")
.to("http://{{service:FOO}}/myapp");<route>
<from uri="direct:start"/>
<to uri="http://{{service:FOO}}/myapp"/>
</route>- route:
from:
uri: direct:start
steps:
- to:
uri: "http://{{service:FOO}}/myapp"如果服务尚未定义,我们可以提供默认值,例如用于单元测试时调用 localhost 上的服务。
- Java
- XML
- YAML
from("direct:start")
.to("http://{{service:FOO:localhost:8080}}/myapp");<route>
<from uri="direct:start"/>
<to uri="http://{{service:FOO:localhost:8080}}/myapp"/>
</route>- route:
from:
uri: direct:start
steps:
- to:
uri: "http://{{service:FOO:localhost:8080}}/myapp"bean 函数(需要在 classpath 中包含 camel-bean JAR)用于从 bean 方法的返回值中查找属性。
假设我们注册了一个名为 foo 的 bean,它有一个名为 bar 的方法,该方法返回一个目录名,那么我们可以在 Camel 端点 URL 中引用该 bean 的方法,并使用 file 组件轮询该目录:
- Java
- XML
- YAML
from("file:{{bean:foo.bar}}")
.to("direct:result");<route>
<from uri="file:{{bean:foo.bar}}"/>
<to uri="direct:result"/>
</route>- route:
from:
uri: file:{{bean:foo.bar}}
steps:
- to:
uri: "direct:result"| 该方法必须是公共的无参方法(即没有参数),并且返回一个值,例如 String、boolean、int。 |
|---|
使用 Kubernetes 属性占位符函数
camel-kubernetes 组件包含以下函数:
configmap- 用于从 Kubernetes ConfigMap 中查找字符串属性的函数。configmap-binary- 用于从 Kubernetes ConfigMap 中查找二进制属性的函数。secret- 用于从 Kubernetes Secret 中查找字符串属性的函数。secret-binary- 用于从 Kubernetes Secret 中查找二进制属性的函数。
这两个函数的语法为:
configmap:name/key[:defaultValue]默认值是可选的,例如下面的例子会查找 myKey,如果不存在这样的 configmap 则会失败。
configmap:mymap/mykey因此,在这个示例中,由于提供了默认值,它不会失败:
configmap:mymap/mykey:123如果存储在 configmap 中的值是二进制格式(即以 Binary Data 形式存储),则会将其下载为一个文件,并返回该文件的绝对路径。
configmap-binary:mymap/mybinkey它会返回类似 /tmp/camel11787545916150467474/mybinkey 的路径
在使用 Kubernetes 属性占位符函数之前,需要先对其进行配置,可配置以下一项(或两项都配置):
- path - 一个挂载路径,必须挂载到正在运行的 Pod 上,以便从本地磁盘加载 ConfigMap 或 Secret。
- kubernetes client - 自动装配(Autowired) 一个
io.fabric8.kubernetes.client.KubernetesClient实例,用于连接 Kubernetes API 服务器。
Camel 会首先使用挂载路径(如果已配置)进行查找,若未配置则回退使用 KubernetesClient。
为 ConfigMap 和 Secret 配置挂载路径
挂载路径的配置按以下优先顺序读取:
- 读取配置属性,键为
camel.kubernetes-config.mount-path-configmaps和camel.kubernetes-config.mount-path-secrets。 - 使用 JVM 系统属性,键为
camel.k.mount-path.configmaps和camel.k.mount-path.secrets(与 Camel K 兼容)。 - 使用操作系统环境变量,键为
CAMEL_K_MOUNT_PATH_CONFIGMAPS和CAMEL_K_MOUNT_PATH_SECRETS(与 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 客户端
如果运行中的应用程序里只存在一个客户端实例(通过 Registry 查找),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 拥有许多选项,更多详情请参阅 Kubernetes Client 文档。 |
|---|
如果你只使用挂载路径,那么最好禁用 KubernetesClient,只需将 enabled 设置为 false 即可,如下所示:
camel.kubernetes-config.client-enabled = false当在现有的 Kubernetes 集群中运行 Camel 应用时,通常无需显式配置 KubernetesClient,可以直接依赖默认设置。
如果你使用 Camel Quarkus,建议使用其 https://quarkus.io/guides/kubernetes-config,它会自动预先配置 KubernetesClient,随后 Camel 会复用该客户端。 |
|---|
在 Kubernetes 中使用 configmap
假设 Kubernetes 中有一个名为 myconfig 的 configmap,其中包含两条条目:
drink = beer
first = Carlsberg然后这些值可以在你的 Camel 路由中使用,例如:
- Java
- XML
- YAML
from("direct:start")
.log("What {{configmap:myconfig/drink}} do you want?")
.log("I want {{configmap:myconfig/first}}"); <route>
<from uri="direct:start"/>
<log message="What {{configmap:myconfig/drink}} do you want?"/>
<log message="I want {{configmap:myconfig/first}}"/>
</route>- route:
from:
uri: direct:start
steps:
- log:
message: "What {{configmap:myconfig/drink}} do you want?"
- log:
message: "I want {{configmap:myconfig/first}}"你还可以为键不存在的情况提供默认值,例如将 Heiniken 作为默认值:
- Java
- XML
- YAML
from("direct:start")
.log("What {{configmap:myconfig/drink}} do you want?")
.log("I want {{configmap:myconfig/second:Heineken}}"); <route>
<from uri="direct:start"/>
<log message="What {{configmap:myconfig/drink}} do you want?"/>
<log message="I want {{configmap:myconfig/second:Heineken}}"/>
</route>- route:
from:
uri: direct:start
steps:
- log:
message: "What {{configmap:myconfig/drink}} do you want?"
- log:
message: "I want {{configmap:myconfig/second:Heineken}}"在 Kubernetes 中使用 Secret
Camel 会从 Kubernetes API Server 读取 ConfigMap。当集群启用了 RBAC 时,用于运行应用程序的 ServiceAccount 必须具备相应的权限才能进行此类访问。
一个名为 mydb 的 Secret 可能包含用于连接数据库的用户名和密码,例如:
myhost = killroy
myport = 5555
myuser = scott
mypass = tiger这可以在 Camel 中使用,例如配合 Postgres Sink Kamelet:
- Java
- XML
- YAML
String sink =
"""
kamelet:postgresql-sink?serverName={{secret:mydb/myhost}}?
&serverPort={{secret:mydb/myport}}
&username={{secret:mydb/myuser}}
&password={{secret:mydb/mypass}}
&databaseName=cities
&query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)
""";
from("direct:rome")
.setBody(constant("{ \"username\":\"oscerd\", \"city\":\"Rome\"}"))
.to(sink); <route>
<from uri="direct:rome"/>
<setBody>
<constant>{ "username":"oscerd", "city":"Rome"}</constant>
</setBody>
<to uri="kamelet:postgresql-sink?serverName={{secret:mydb/myhost}}
&serverPort={{secret:mydb/myport}}
&username={{secret:mydb/myuser}}
&password={{secret:mydb/mypass}}
&databaseName=cities
&query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/>
</route>- route:
from:
uri: direct
parameters:
name: rome
steps:
- setBody:
expression:
constant:
expression: "{ \"username\":\"oscerd\", \"city\":\"Rome\"}"
- to:
uri: kamelet
parameters:
templateId: postgresql-sink
serverName: "{{secret:mydb/myhost}}"
serverPort: "{{secret:mydb/myport}}"
username: "{{secret:mydb/myuser}}"
password: "{{secret:mydb/mypass}}"
databaseName: 'cities'
query: "INSERT INTO accounts (username,city) VALUES (:#username,:#city)"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}}这会将路由简化为:
- Java
- XML
- YAML
from("direct:rome")
.setBody(constant("{ \"username\":\"oscerd\", \"city\":\"Rome\"}"))
.to("kamelet:postgresql-sink?databaseName=cities&query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"); <route>
<from uri="direct:rome"/>
<setBody>
<constant>{ "username":"oscerd", "city":"Rome"}</constant>
</setBody>
<to uri="kamelet:postgresql-sink?databaseName=cities
&query=INSERT INTO accounts (username,city) VALUES (:#username,:#city)"/>
</route>- route:
from:
uri: direct:rome
steps:
- setBody:
expression:
constant:
expression: "{ \"username\":\"oscerd\", \"city\":\"Rome\"}"
- to:
uri: kamelet
parameters:
templateId: postgresql-sink
databaseName: cities
query: "INSERT INTO accounts (username,city) VALUES (:#username,:#city)"在本地模式中使用 configmap 或 secret
在开发过程中,你可能希望以本地模式运行,此时无需访问 Kubernetes 集群即可查找 configmap。在本地模式下,Camel 将从本地属性中查找 configmap 的键,例如:
例如,上面使用 Postgres kamelet 并通过 secret 进行配置的示例:
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}}现在假设我们有一个本地 Postgres 数据库需要使用,那么我们可以开启本地模式,并在同一个属性文件中指定凭据:
camel.kubernetes-config.local-mode = true
mydb/myhost=localhost
mydb/myport=1234
mydb/myuser=scott
mydb/mypass=tiger注意,键前面带有 Secret 名称和一个斜杠,例如 name/key。这样就便于从 configmap/secret 的实际使用处复制粘贴到 application.properties 文件中。 |
|---|
使用自定义属性占位符函数
Properties 组件允许接入第三方函数,这些函数可以在解析属性占位符时被使用。随后,这些函数可以执行自定义逻辑来解析占位符,例如查询数据库、进行自定义计算等。函数的名称会成为占位符中使用的前缀。
下面的示例路由最能说明这一点,我们在其中使用 beer 作为前缀:
- Java
- XML
- YAML
from("direct:start")
.to("{{beer:FOO}}")
.to("{{beer:BAR}}");<route>
<from uri="direct:start"/>
<to uri="{{beer:FOO}}"/>
<to uri="{{beer:BAR}}"/>
</route>- route:
from:
uri: direct:start
steps:
- to:
uri: "{{beer:FOO}}"
- to:
uri: "{{beer:BAR}}"该函数的实现仅需两个方法,如下所示:
@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 方法用于返回函数的名称(beer),而 apply 方法则用来实现自定义的处理逻辑。由于示例代码取自单元测试,它只返回一个用于引用模拟端点的值。
你还需要在构建该组件时包含 camel-component-maven-plugin Maven 插件,它将确保为这个自定义属性函数生成必要的源代码,从而使 Camel 能够自动发现该函数。
如果自定义属性函数需要在启动和停止时执行逻辑,那么该函数可以继承 ServiceSupport,并将这些逻辑放在 doStart 和 doStop 方法中。 |
|---|
相关示例可参见 camel-base64 组件。 |
|---|
评论
登录后参与评论
KnowForge