46.3. 生成的组件子项目
概述
用于构建新组件的 Maven 子项目位于 camel-api-example/camel-api-example-component
项目目录下。在本节中,我们仔细查看生成的示例代码,并描述它的工作原理。
在组件 POM 中提供 Java API
Java API 必须作为组件 POM 中的依赖项提供。例如,示例 Java API 在组件 POM 文件中被定义为依赖项,camel-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 元数据
如果您将 Javadoc 元数据用于 Java API 的所有或部分,则必须提供 Javadoc 作为组件 POM 中的依赖项。关于这个依赖项需要注意两个事项:
Javadoc 的 Maven 协调与 Java API 的几乎相同,但您必须指定一个
classifier
元素,如下所示:<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
,位于 camel-api-example-component/signatures
中,其中包含以下内容:
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
元素配置,其中包含一个用于配置 Java API 类的 apis
子元素。每个 API 类都由 api
元素配置,如下所示:
apiName
API 名称是 API 类的短名称,用作端点 URI 的
endpoint-prefix
部分。注意如果 API 仅包含单个 Java 类,您可以将
apiName
元素留空,以便endpoint-prefix
变得冗余,然后使用 “单个 API 类的 URI 格式”一节 中显示的格式指定端点 URI。proxyClass
- proxy class 元素指定 API 类的完全限定域名。
fromJavadoc
-
如果 API 类附带有 Javadoc 元数据,则必须通过
包含来自Javadoc
元素的 Javadoc 元素,且 Javadoc 本身还必须在 Maven 文件中指定,作为提供的
依赖项(请参阅 “在组件 POM 中提供 Javadoc 元数据”一节)。 fromSignatureFile
如果 API 类由签名文件元数据提供,您必须通过包含
fromSignatureFile
元素来指示它,其中此元素的内容指定签名文件的位置。注意签名文件不会包含在 Maven 构建的最终软件包中,因为这些文件仅在构建时需要,而不是在运行时。
生成的组件实现
API 组件由以下核心类(必须为每个 Camel 组件实施)组成,在 camel-api-example-component/src/main/java
目录下:
ExampleComponent
-
代表组件本身。此类充当端点实例的工厂(例如,
ExampleEndpoint
的实例)。 ExampleEndpoint
-
代表端点 URI。此类充当消费者端点的工厂(如
ExampleConsumer
)和生成者端点的工厂(如Producer
)。 ExampleConsumer
- 代表消费者端点的一个特定实例,它能够消耗来自端点 URI 中指定的位置的消息。
ExampleProducer
- 代表制作者端点的协调实例,它可以发送消息到端点 URI 中指定的位置。
ExampleConfiguration
可用于定义端点 URI 选项。此配置类定义的 URI 选项 不与任何 特定的 API 类关联。也就是说,您可以将这些 URI 选项与任何 API 类或方法组合。例如,如果您需要声明用户名和密码凭证以连接到远程服务,这非常有用。
ExampleConfiguration
类的主要目的是,为实例化 API 类或实施 API 接口的类提供所需的参数值。例如,它们可以是 constructor 参数,也可以是 factory 方法或类的参数值。要实施 URI 选项,
选项
,在此类中,您需要做的一切都实施对访问器方法,获得
。组件框架自动解析端点 URI,并在运行时注入选项值。选项和
设置选项
ExampleComponent class
生成的 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
,它会创建新的端点实例。通常,您不需要更改组件类中的任何默认代码。如果存在与这个组件相同的生命周期的其他对象,但您可能希望将这些对象从组件类提供(例如,通过添加方法来创建这些对象或将这些对象注入组件)。
Endpoint 类示例
生成的 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 具有通用形式,scheme://
)。
endpoint-prefix
/端点
ExampleConsumer class
生成的 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 选项 选项
,请在该类中定义相应类型的字段,并实施相应的访问器方法对,getOption
和 setOption
。组件框架自动解析端点 URI,并在运行时注入选项值。
此类用于定义 常规 URI 选项,可与任何 API 方法结合使用。要定义与特定 API 方法关联的 URI 选项,请在 API 组件 Maven 插件中配置额外的选项。详情请查看 第 47.7 节 “额外选项”。
URI 格式
回想 API 组件 URI 的一般格式:
scheme://endpoint-prefix/endpoint?Option1=Value1&...&OptionN=ValueN
通常,URI 映射到 Java API 上的特定方法调用。例如,假设您想调用 API 方法,如 JavadocHello.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
。如果要为选项定义默认值,可以通过覆盖拦截器Properties
方法(请参阅 第 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
组件的默认实例。如果您重构组件类的名称,您才需要编辑此文件。