2.7. 属性 Placeholders
概述
属性占位符功能可用于将字符串替换为各种上下文(如 XML DSL 元素中的端点 URI 和属性),其中占位符设置存储在 Java 属性文件中。如果要在不同的 Apache Camel 应用程序之间共享设置,或者要集中某些配置设置,则此功能很有用。
例如,以下路由将请求发送到 Web 服务器,其主机和端口由占位符替换,{{remote.host}}
和 {{remote.port}}
:
from("direct:start").to("http://{{remote.host}}:{{remote.port}}");
占位符值在 Java 属性文件中定义,如下所示:
# Java properties file remote.host=myserver.com remote.port=8080
属性 Placeholders 支持一个编码选项,它允许您使用特定字符集(如 UTF-8 )读取 .properties
文件。但是,默认情况下,它会实现 ISO-8859-1 字符集。
使用 PropertyPlaceholders
的 Apache Camel 支持以下内容:
- 将默认值与要查找的键一起使用。
-
如果所有占位符键都包含默认值,则不需要定义
PropertiesComponent
。 使用第三方函数查找属性值。它使您能够实施自己的逻辑。
注意提供三个开箱即用功能,以便从 OS 环境变量、JVM 系统属性或服务名称 idiom 查找值。
属性文件
属性设置存储在一个或多个 Java 属性文件中,必须符合标准的 Java 属性文件格式。每个属性设置都显示在其自己的行中,格式为 Key=Value
。带有 @
或 !
的行作为第一个非空字符被认为是注释。
例如,属性文件可以包含内容,如 例 2.4 “属性文件示例” 所示。
例 2.4. 属性文件示例
# Property placeholder settings # (in Java properties file format) cool.end=mock:result cool.result=result cool.concat=mock:{{cool.result}} cool.start=direct:cool cool.showid=true cheese.end=mock:cheese cheese.quote=Camel rocks cheese.type=Gouda bean.foo=foo bean.bar=bar
解决属性
属性组件必须配置有一个或多个属性文件的位置,然后才能在路由定义中使用它。您必须使用以下解析器之一提供属性值:
classpath:PathName,PathName,…
- (默认) 指定 classpath 上的位置,其中 PathName 是用正斜杠分隔的文件路径名。
file:PathName,PathName,…
- 指定文件系统的位置,其中 PathName 是用正斜杠分隔的文件路径名。
ref:BeanID
-
指定 registry 中
java.util.Properties
对象的 ID。 蓝图:BeanID
-
指定
cm:property-placeholder
bean 的 ID,它用于 OSGi 蓝图文件的上下文,以访问 OSGi 配置管理员 服务中定义的属性。详情请查看 “与 OSGi 蓝图属性占位符集成”一节。
例如,要指定 com/fusesource/cheese.properties
属性文件和 com/fusesource/bar.properties
属性文件(位于 classpath 上),您可以使用以下位置字符串:
com/fusesource/cheese.properties,com/fusesource/bar.properties
您可以省略本例中的 classpath:
前缀,因为 classpath 解析器被默认使用。
使用系统属性和环境变量指定位置
您可以在 location PathName 中嵌入 Java 系统属性和 O/S 环境变量。
可以使用语法 ${PropertyName}
将 Java 系统属性嵌入到位置解析器中。例如,如果 Red Hat Fuse 的根目录存储在 Java 系统属性 karaf.home
中,您可以在文件位置嵌入该目录值,如下所示:
file:${karaf.home}/etc/foo.properties
O/S 环境变量可以使用语法 ${env:VarName}
嵌入到位置解析器中。例如,如果 JBoss Fuse 的根目录存储在环境变量 SMX_HOME
中,您可以将该目录值嵌入到文件位置中,如下所示:
file:${env:SMX_HOME}/etc/foo.properties
配置属性组件
在开始使用属性占位符前,您必须配置属性组件,并指定一个或多个属性文件的位置。
在 Java DSL 中,您可以使用属性文件位置配置属性组件,如下所示:
// Java import org.apache.camel.component.properties.PropertiesComponent; ... PropertiesComponent pc = new PropertiesComponent(); pc.setLocation("com/fusesource/cheese.properties,com/fusesource/bar.properties"); context.addComponent("properties", pc);
如 addComponent ()
调用中所示,属性组件的名称 必须设置为 属性
。
在 XML DSL 中,您可以使用 dedicated propertyPlacholder
元素配置属性组件,如下所示:
<camelContext ...> <propertyPlaceholder id="properties" location="com/fusesource/cheese.properties,com/fusesource/bar.properties" /> </camelContext>
如果您希望属性组件在初始化时忽略任何缺少的 .properties
文件,您可以将 ignoreMissingLocation
选项设置为 true
(通常,缺少的 .properties
文件会导致引发错误)。
另外,如果您希望属性组件忽略任何使用 Java 系统属性或 O/S 环境变量指定的缺失位置,您可以将 ignoreMissingLocation
选项设置为 true
。
占位符语法
配置后,属性组件会自动替换占位符(在适当的上下文中)。占位符的语法取决于上下文,如下所示:
-
在端点 URI 和 Spring XML 文件中 ,需要把占位符指定为 {{
Key}}
。 在设置 XML DSL 属性 swig-
xs:string
属性时,使用以下语法设置:AttributeName="{{Key}}"
其它属性类型(如
xs:int
或xs:boolean
)必须使用以下语法设置:prop:AttributeName="Key"
其中
prop
与http://camel.apache.org/schema/placeholder
命名空间关联。当设置 Java DSL EIP 选项 swig-wagonto 对 Java DSL 中的企业集成模式(EIP)命令设置选项时,在 fluent DSL 中添加如下
占位符()
子句:.placeholder("OptionName", "Key")
-
在 Simple language 表达式中 ,您会将占位符指定为
${properties:Key}
。
在端点 URI 中替换
每当端点 URI 字符串出现在路由中时,解析端点 URI 的第一步都会应用属性占位符解析器。占位符解析器自动替换在双花括号 {{ Key}}
之间出现的任何属性名称。例如,给定 例 2.4 “属性文件示例” 中显示的属性设置,您可以定义路由,如下所示:
from("{{cool.start}}") .to("log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}") .to("mock:{{cool.result}}");
默认情况下,占位符解析器会在 registry 中查找 属性
Bean ID 来查找属性组件。如果愿意,您可以在端点 URI 中明确指定方案。例如,通过为每个端点 URI 前缀 属性
,您可以定义以下等同的路由:
from("properties:{{cool.start}}") .to("properties:log:{{cool.start}}?showBodyType=false&showExchangeId={{cool.showid}}") .to("properties:mock:{{cool.result}}");
当明确指定方案时,您还可以选择在属性组件中指定选项。例如,要覆盖属性文件位置,您可以按照如下所示设置 location
选项:
from("direct:start").to("properties:{{bar.end}}?location=com/mycompany/bar.properties");
在 Spring XML 文件中替换
您还可以在 XML DSL 中使用属性占位符来设置 DSL 元素的各种属性。在这种情况下,placholder 语法也使用双括号 {{ Key}}
。例如,您可以使用属性占位符定义 jmxAgent
元素,如下所示:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" location="org/apache/camel/spring/jmx.properties"/> <!-- we can use property placeholders when we define the JMX agent --> <jmxAgent id="agent" registryPort="{{myjmx.port}}" usePlatformMBeanServer="{{myjmx.usePlatform}}" createConnector="true" statisticsLevel="RoutesOnly" /> <route> <from uri="seda:start"/> <to uri="mock:result"/> </route> </camelContext>
替换 XML DSL 属性值
您可以使用常规占位符语法来指定 xs:string
type swig-5-4 等属性值,例如 < jmxAgent registryPort="{{myjmx.port}}" …
>。但是对于任何其他类型的属性(例如 xs:int
或 xs:boolean
),您必须使用特殊语法 prop:AttributeName="Key"
。
例如,假设属性文件定义了 stop.flag
属性,使其具有值 true
,您可以使用此属性设置 stopOnException
布尔值属性,如下所示:
<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" ... > <bean id="illegal" class="java.lang.IllegalArgumentException"> <constructor-arg index="0" value="Good grief!"/> </bean> <camelContext xmlns="http://camel.apache.org/schema/spring"> <propertyPlaceholder id="properties" location="classpath:org/apache/camel/component/properties/myprop.properties" xmlns="http://camel.apache.org/schema/spring"/> <route> <from uri="direct:start"/> <multicast prop:stopOnException="stop.flag"> <to uri="mock:a"/> <throwException ref="damn"/> <to uri="mock:b"/> </multicast> </route> </camelContext> </beans>
prop
前缀必须明确分配给 Spring 文件中的 http://camel.apache.org/schema/placeholder
命名空间,如上例的 Bean
元素中所示。
替换 Java DSL EIP 选项
在 Java DSL 中调用 EIP 命令时,您可以使用属性占位符值来设置任何 EIP 选项,方法是添加表单的子使用,占位符("OptionName", "Key")
。
例如,如果属性文件定义了 stop.flag
属性为值 true
,您可以使用此属性设置 multicast EIP 的 stopOnException
选项,如下所示:
from("direct:start") .multicast().placeholder("stopOnException", "stop.flag") .to("mock:a").throwException(new IllegalAccessException("Damn")).to("mock:b");
使用简单语言表达式替换
您还可以使用简单语言表达式替换属性占位符,但在这种情况下,占位符的语法为 ${properties:Key}
。例如,您可以在简单表达式中替换 cheese.quote
占位符,如下所示:
from("direct:start") .transform().simple("Hi ${body} do you think ${properties:cheese.quote}?");
您可以使用语法 ${properties:Key:DefaultVal}
来指定属性的默认值。例如:
from("direct:start") .transform().simple("Hi ${body} do you think ${properties:cheese.quote:cheese is good}?");
也可以使用语法 ${properties-location:Location:Key}
来覆盖属性文件的位置。例如,要使用 com/mycompany/bar.properties
属性文件中的设置替换 bar.quote
占位符,您可以定义一个简单表达式,如下所示:
from("direct:start") .transform().simple("Hi ${body}. ${properties-location:com/mycompany/bar.properties:bar.quote}.");
在 XML DSL 中使用 Property Placeholders
在较旧的版本中,xs:string
类型属性用于支持 XML DSL 中的占位符。例如,timeout 属性将是 xs:int
类型。因此,您无法将字符串值设置为占位符键。
从 Apache Camel 2.7 开始,现在可以使用特殊的占位符命名空间来实现。以下示例演示了命名空间的 prop 前缀。它允许您在 XML DSLs 中的属性中使用 prop 前缀。
在 Multicast 中,将选项 stopOnException
设置为占位符的值,其键为 stop
。另外,在属性文件中,将值定义为
stop=true
<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 "> <!-- Notice in the declaration above, we have defined the prop prefix as the Camel placeholder namespace --> <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:org/apache/camel/component/properties/myprop.properties" xmlns="http://camel.apache.org/schema/spring"/> <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>
与 OSGi 蓝图属性占位符集成
如果您将路由部署到红帽 Fuse OSGi 容器中,您可以将 Apache Camel 属性占位符机制与 JBoss Fuse 的蓝图属性占位符机制集成(实际上,集成默认为启用)。设置集成有两种基本方法,如下所示:
隐式蓝图集成
如果您在 OSGi 蓝图文件中定义了 camelContext
元素,则 Apache Camel 属性占位符机制会自动与蓝图属性占位符机制集成。也就是说,在 camelContext
范围内出现的 Apache Camel 语法(如 {{cool.end}}
)的占位符可以通过查找 蓝图属性占位符 机制来隐式解析。
例如,请考虑以下路由,在 OSGi 蓝图文件中定义,其中路由中的最后一个端点由属性占位符定义,{{result}}
:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <!-- OSGI blueprint property placeholder --> <cm:property-placeholder id="myblueprint.placeholder" persistent-id="camel.blueprint"> <!-- list some properties for this test --> <cm:default-properties> <cm:property name="result" value="mock:result"/> </cm:default-properties> </cm:property-placeholder> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <!-- in the route we can use {{ }} placeholders which will look up in blueprint, as Camel will auto detect the OSGi blueprint property placeholder and use it --> <route> <from uri="direct:start"/> <to uri="mock:foo"/> <to uri="{{result}}"/> </route> </camelContext> </blueprint>
蓝图属性占位符机制通过创建 cm:property-placeholder
bean 初始化。在前面的示例中,cm:property-placeholder
bean 与 camel.blueprint
持久 ID 关联,其中持久 ID 是引用 OSGi 配置管理员 服务中一组相关属性的标准方法。换句话说,cm:property-placeholder
bean 提供对 camel.blueprint
持久 ID 下定义的所有属性的访问。还可以为某些属性指定默认值(使用嵌套的 cm:property
元素)。
在蓝图的上下文中,Apache Camel 占位符机制在 bean registry 中搜索 cm:property-placeholder
实例。如果找到这样的实例,它会自动集成 Apache Camel 占位符机制,以便占位符(如 {{result}}
)可以通过在蓝图属性占位符机制中查找密钥来解决(本例中为通过 myblueprint.placeholder
bean)。
默认蓝图占位符语法(直接访问蓝图属性)是 ${Key}
。因此,在 camelContext
元素范围内,您必须使用的占位符语法为 ${Key}
。而在 camelContext
元素的范围内,您必须使用的占位符语法为 {{ Key}}
。
显式蓝图集成
如果要对 Apache Camel 属性占位符机制在哪里找到其属性,您可以定义 propertyPlaceholder
元素并明确指定解析器位置。
例如,请考虑以下蓝图配置,它与前一个示例不同,它创建一个明确的 propertyPlaceholder
实例:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 ">https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <!-- OSGI blueprint property placeholder --> <cm:property-placeholder id="myblueprint.placeholder" persistent-id="camel.blueprint"> <!-- list some properties for this test --> <cm:default-properties> <cm:property name="result" value="mock:result"/> </cm:default-properties> </cm:property-placeholder> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <!-- using Camel properties component and refer to the blueprint property placeholder by its id --> <propertyPlaceholder id="properties" location="blueprint:myblueprint.placeholder"/> <!-- in the route we can use {{ }} placeholders which will lookup in blueprint --> <route> <from uri="direct:start"/> <to uri="mock:foo"/> <to uri="{{result}}"/> </route> </camelContext> </blueprint>
在前面的示例中,propertyPlaceholder
元素通过将位置设置为 blueprint:myblueprint.placeholder
来指定要使用的 cm:property-placeholder
bean。也就是说,蓝图:
解析器明确引用了 cm:property-placeholder
bean 的 ID myblueprint.placeholder
。
如果蓝图文件中定义了多个 cm:property-placeholder
bean,且您需要指定要使用的配置,则这种配置很有用。您还可以通过指定以逗号分隔的位置列表,从多个位置的源属性。例如,如果要从 cm:property-placeholder
bean 和 properties 文件 myproperties.properties
中查找属性,您可以在 classpath 上定义 propertyPlaceholder
元素,如下所示:
<propertyPlaceholder id="properties" location="blueprint:myblueprint.placeholder,classpath:myproperties.properties"/>
与 Spring 属性占位符集成
如果您在 Spring XML 文件中使用 XML DSL 定义 Apache Camel 应用程序,您可以通过声明 Spring bean 类型 org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer
将 Apache Camel 属性占位符机制集成。
定义 BridgePropertyPlaceholderConfigurer
,它取代了 Apache Camel 的 propertyPlaceholder
元素和 Spring 的 ctx:property-placeholder
元素。然后,您可以使用 Spring ${PropName}
语法或 Apache Camel {{ PropName}}
语法引用配置的属性。
例如,定义一个 bridge 属性占位符,从 cheese.properties
文件中读取其属性设置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ctx="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Bridge Spring property placeholder with Camel --> <!-- Do not use <ctx:property-placeholder ... > at the same time --> <bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer"> <property name="location" value="classpath:org/apache/camel/component/properties/cheese.properties"/> </bean> <!-- 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"> <!-- Use Camel's property placeholder {{ }} style --> <route> <from uri="direct:{{cool.bar}}"/> <bean ref="hello"/> <to uri="{{cool.end}}"/> </route> </camelContext> </beans>
或者,您可以将 BridgePropertyPlaceholderConfigurer
的 location
属性设置为指向 Spring 属性文件。Spring 属性文件语法被完全支持。