46.3. 生成的组件子项目
概述
用于构建新组件的 Maven 子项目位于 camel-api-example/camel-api-example-component
项目目录下。在本节中,我们会仔细查看生成的示例代码,并描述其工作原理。
在组件 POM 中提供 Java API
Java API 必须作为组件 POM 中的依赖项提供。例如,示例 Java API 在组件 POM 文件中定义为依赖项,cal -api-example-component/pom.xml
如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <dependencies> ... <dependency> <groupId>org.jboss.fuse.example</groupId> <artifactId>camel-api-example-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> ... </dependencies> ... </project>
在组件 POM 中提供 Javadoc 元数据
如果您使用 Java API 的所有或部分的 Javadoc 元数据,则必须在组件 POM 中以依赖项形式提供 Javadoc。关于这个依赖关系,有两个问题:
Javadoc 的 Maven 协调几乎和 Java API 相同,但您还必须指定类
符
元素,如下所示:<classifier>javadoc</classifier>
您必须声明 Javadoc 以
提供范围
,如下所示:<scope>provided</scope>
例如,在组件 POM 中,Javadoc 依赖项定义如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <dependencies> ... <!-- Component API javadoc in provided scope to read API signatures --> <dependency> <groupId>org.jboss.fuse.example</groupId> <artifactId>camel-api-example-api</artifactId> <version>1.0-SNAPSHOT</version> <classifier>javadoc</classifier> <scope>provided</scope> </dependency> ... </dependencies> ... </project>
为示例文件 Hello 定义文件元数据
ExampleFileHello
的元数据在签名文件中提供。通常,必须手动创建此文件,但是它的格式非常简单,它由一个方法签名列表(每行一个)组成。示例代码在 目录中提供了签名文件 file-sig
,它包含以下内容:
-api
.txt
public String sayHi(); public String greetMe(String name); public String greetUs(String name1, String name2);
有关签名文件格式的详情,请参考 “签名文件元数据”一节。
配置 API 映射
API 组件框架的主要功能之一是它自动生成代码来执行 API 映射。也就是说,生成存根代码,将端点 URI 映射到 Java API 上调用的方法。API 映射的基本输入有:Java API、Javadoc 元数据和/或签名文件元数据。
执行 API 映射的组件是 camel-api-component-maven-plugin
Maven 插件,它在组件 POM 中配置。以下从组件 POM 中提取的显示了如何配置 camel-api-component-maven-plugin
插件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> ... <build> <defaultGoal>install</defaultGoal> <plugins> ... <!-- generate Component source and test source --> <plugin> <groupId>org.apache.camel</groupId> <artifactId>camel-api-component-maven-plugin</artifactId> <executions> <execution> <id>generate-test-component-classes</id> <goals> <goal>fromApis</goal> </goals> <configuration> <apis> <api> <apiName>hello-file</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleFileHello</proxyClass> <fromSignatureFile>signatures/file-sig-api.txt</fromSignatureFile> </api> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> </apis> </configuration> </execution> </executions> </plugin> ... </plugins> ... </build> ... </project>
该插件由 configuration
元素配置,其中包含一个 apis
子元素来配置 Java API 类。每个 API 类都由一个 api
元素配置,如下所示:
apiName
API 名称是 API 类的简短名称,用作
端点 URI 的端点前缀
部分。注意如果 API 只包含一个 Java 类,您可以将
apiName
元素留空,以便endpoint-prefix
变为冗余,您可以使用 “单个 API 类的 URI 格式”一节 所示的格式指定端点 URI。proxyClass
- proxy class 元素指定 API 类的完全限定名称。
fromJavadoc
-
如果 API 类由 Javadoc 元数据提供,您必须通过包含
fromJavadoc
元素和 Javadoc 本身在 Maven 文件中指定它,作为提供的
依赖项(请参阅 “在组件 POM 中提供 Javadoc 元数据”一节)。 fromSignatureFile
如果 API 类使用签名文件元数据,您必须通过包含
fromSignatureFile
元素来指明这一点,此元素的内容指定了签名文件的位置。注意签名文件不包括在 Maven 构建的最终软件包中,因为这些文件仅在构建时不需要。
生成的组件实施
API 组件由以下核心类(必须为每个 Camel 组件实施)位于 camel-api-example-component/src/main/java
目录下:
Component 示例
-
代表组件本身。此类充当端点实例的工厂(如
ExampleEndpoint
的实例)。 示例Endpoint
-
代表端点 URI。此类充当消费者端点的工厂(例如,
ExampleConsumer
)和制作者端点的工厂(如示例Producer
)。 Consumer 示例
- 代表消费者端点的声明实例,该端点能够使用来自端点 URI 中指定的位置的消息。
Producer 示例
- 代表制作者端点的 concrete 实例,它能够将消息发送到端点 URI 中指定的位置。
ExampleConfiguration
可用于定义端点 URI 选项。此配置类定义的 URI 选项 不 绑定到任何特定的 API 类。也就是说,您可以将这些 URI 选项与任何 API 类或方法组合。例如,如果您需要声明用户名和密码凭证才能连接到远程服务,这将会很有用。
ExampleConfiguration
类的主要目的是提供实例化 API 类或实施 API 接口所需的参数的值。例如,这些可以是构造参数,也可以是工厂方法或类的参数值。要实现 URI 选项(在这一类中),您需要做的所有选项都是实施访问器方法对,
获取选项和设置选项
。组件框架自动解析端点 URI,并在运行时注入选项值。
Component 类示例
生成的 ExampleComponent
类定义如下:
// Java package org.jboss.fuse.example; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.util.component.AbstractApiComponent; import org.jboss.fuse.example.internal.ExampleApiCollection; import org.jboss.fuse.example.internal.ExampleApiName; /** * Represents the component that manages {@link ExampleEndpoint}. */ @UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer") public class ExampleComponent extends AbstractApiComponent<ExampleApiName, ExampleConfiguration, ExampleApiCollection> { public ExampleComponent() { super(ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection()); } public ExampleComponent(CamelContext context) { super(context, ExampleEndpoint.class, ExampleApiName.class, ExampleApiCollection.getCollection()); } @Override protected ExampleApiName getApiName(String apiNameStr) throws IllegalArgumentException { return ExampleApiName.fromValue(apiNameStr); } @Override protected Endpoint createEndpoint(String uri, String methodName, ExampleApiName apiName, ExampleConfiguration endpointConfiguration) { return new ExampleEndpoint(uri, this, apiName, methodName, endpointConfiguration); } }
此类中的重要方法是 createEndpoint
,它用于创建新的端点实例。通常,您不需要更改组件类中的任何默认代码。但是,如果存在与这个组件相同的生命周期其他任何对象,您可能想让这些对象从组件类访问(例如,通过添加方法来创建这些对象或通过将这些对象注入组件)。
ExampleEndpoint 类
生成的 ExampleEndpoint
类定义如下:
// Java package org.jboss.fuse.example; import java.util.Map; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.util.component.AbstractApiEndpoint; import org.apache.camel.util.component.ApiMethod; import org.apache.camel.util.component.ApiMethodPropertiesHelper; import org.jboss.fuse.example.api.ExampleFileHello; import org.jboss.fuse.example.api.ExampleJavadocHello; import org.jboss.fuse.example.internal.ExampleApiCollection; import org.jboss.fuse.example.internal.ExampleApiName; import org.jboss.fuse.example.internal.ExampleConstants; import org.jboss.fuse.example.internal.ExamplePropertiesHelper; /** * Represents a Example endpoint. */ @UriEndpoint(scheme = "example", consumerClass = ExampleConsumer.class, consumerPrefix = "consumer") public class ExampleEndpoint extends AbstractApiEndpoint<ExampleApiName, ExampleConfiguration> { // TODO create and manage API proxy private Object apiProxy; public ExampleEndpoint(String uri, ExampleComponent component, ExampleApiName apiName, String methodName, ExampleConfiguration endpointConfiguration) { super(uri, component, apiName, methodName, ExampleApiCollection.getCollection().getHelper(apiName), endpointConfiguration); } public Producer createProducer() throws Exception { return new ExampleProducer(this); } public Consumer createConsumer(Processor processor) throws Exception { // make sure inBody is not set for consumers if (inBody != null) { throw new IllegalArgumentException("Option inBody is not supported for consumer endpoint"); } final ExampleConsumer consumer = new ExampleConsumer(this, processor); // also set consumer.* properties configureConsumer(consumer); return consumer; } @Override protected ApiMethodPropertiesHelper<ExampleConfiguration> getPropertiesHelper() { return ExamplePropertiesHelper.getHelper(); } protected String getThreadProfileName() { return ExampleConstants.THREAD_PROFILE_NAME; } @Override protected void afterConfigureProperties() { // TODO create API proxy, set connection properties, etc. switch (apiName) { case HELLO_FILE: apiProxy = new ExampleFileHello(); break; case HELLO_JAVADOC: apiProxy = new ExampleJavadocHello(); break; default: throw new IllegalArgumentException("Invalid API name " + apiName); } } @Override public Object getApiProxy(ApiMethod method, Map<String, Object> args) { return apiProxy; } }
在 API 组件框架的上下文中,端点类执行的一个关键步骤之一是创建 API 代理。API 代理是一个来自目标 Java API 的实例,其方法由端点调用。因为 Java API 通常由多个类组成,因此需要根据 URI 中出现的端点 前缀
来选择适当的 API 类(所有 URI 具有常规形式,方案://端点前缀/端点
)。
Consumer 类示例
生成的 ExampleConsumer
类定义如下:
// Java package org.jboss.fuse.example; import org.apache.camel.Processor; import org.apache.camel.util.component.AbstractApiConsumer; import org.jboss.fuse.example.internal.ExampleApiName; /** * The Example consumer. */ public class ExampleConsumer extends AbstractApiConsumer<ExampleApiName, ExampleConfiguration> { public ExampleConsumer(ExampleEndpoint endpoint, Processor processor) { super(endpoint, processor); } }
Producer 类示例
生成的 ExampleProducer
类定义如下:
// Java package org.jboss.fuse.example; import org.apache.camel.util.component.AbstractApiProducer; import org.jboss.fuse.example.internal.ExampleApiName; import org.jboss.fuse.example.internal.ExamplePropertiesHelper; /** * The Example producer. */ public class ExampleProducer extends AbstractApiProducer<ExampleApiName, ExampleConfiguration> { public ExampleProducer(ExampleEndpoint endpoint) { super(endpoint, ExamplePropertiesHelper.getHelper()); } }
ExampleConfiguration 类
生成的 ExampleConfiguration
类定义如下:
// Java package org.jboss.fuse.example; import org.apache.camel.spi.UriParams; /** * Component configuration for Example component. */ @UriParams public class ExampleConfiguration { // TODO add component configuration properties }
要添加 URI 选项( 选择
)到此类中,定义相应类型的字段,并实施对应的访问器方法、获取选项和设置选项
。 组件框架自动解析端点 URI,并在运行时注入选项值。
这个类用于定义 常规 URI 选项,可以与任何 API 方法相结合。要定义与特定 API 方法关联的 URI 选项,在 API 组件 Maven 插件中配置额外的选项。详情请查看 第 47.7 节 “额外选项”。
URI 格式
重新调用 API 组件 URI 的一般格式:
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
通常,URI 映射到 Java API 上的特定方法调用。例如,假设您要调用 API 方法,ExampleJavadocHello.greetMe("Jane Doe")
将被构造 URI,如下所示:
- scheme
-
API 组件方案,如使用 Maven archetype 生成代码时所指定。在这种情况下,方案是
示例
。 - endpoint-prefix
API 名称,它映射到由
camel-api-component-maven-plugin
Maven 插件配置定义的 API 类。对于ExampleJavadocHello
类,相关配置为:<configuration> <apis> <api> <apiName>hello-javadoc</apiName> <proxyClass>org.jboss.fuse.example.api.ExampleJavadocHello</proxyClass> <fromJavadoc/> </api> ... </apis> </configuration>
这表明所需的
endpoint-prefix
是hello-javadoc
。- 端点
-
端点
映射到方法名称,即greetMe
。 - Option1=Value1
-
URI 选项指定方法参数。
greetMe(String name)
方法采用单一参数,即名称
,它可以指定为name=Jane%20Doe
。如果要为选项定义默认值,可以通过覆盖interceptProperties
方法(请参阅 第 46.4 节 “编程模型”)。
将 URI 的片段放在一起,我们可以看到您可以使用以下 URI 调用 ExampleJavadocHello.greetMe("Jane Doe")
:
example://hello-javadoc/greetMe?name=Jane%20Doe
默认组件实例
要将 示例
URI 方案映射到默认组件实例,Maven archetype 会在 camel-api-example-component
子项目下创建以下文件:
src/main/resources/META-INF/services/org/apache/camel/component/example
此资源文件是什么使 Camel 内核能够识别与 示例
URI 方案关联的组件。每当您在路由中使用 example://
URI 时,Camel 都会搜索 classpath 以查找对应的 示例
资源文件。示例文件
包含以下内容:
class=org.jboss.fuse.example.ExampleComponent
这可让 Camel 核心创建 ExampleComponent
组件的默认实例。如果您重构了组件类的名称,您需要编辑此文件的唯一时间。