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 元素配置,如下所示:
apiNameAPI 名称是 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-pluginMaven 插件配置定义的 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 组件的默认实例。如果您重构了组件类的名称,您需要编辑此文件的唯一时间。