部署到 JBoss EAP

Red Hat Fuse 7.11

将应用程序软件包部署到 JBoss Enterprise Application Platform(EAP)容器中

Red Hat Fuse Documentation Team

摘要

本指南描述了将应用程序部署到 JBoss EAP 容器中的选项。

使开源包含更多

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。详情请查看我们的 CTO Chris Wright 信息

第 1 章 JBoss EAP 部署中的 JBoss Fuse 概述

在 JBoss 企业应用平台(JBoss EAP)上安装 Fuse 软件包后,便可将 Fuse 应用程序部署到 JBoss EAP 容器中。

本节介绍在 EAP 子系统中使用 Camel 的部署模型。Fuse 中的 Apache Camel 允许您选择容器来运行集成应用程序。

注意

红帽 JBoss EAP 具有一系列应用程序部署和配置选项,可促进管理员和开发人员。如需有关 JBOSS EAP 配置和部署流程的更多信息,请参阅红帽 JBoss EAP 配置指南

1.1. 支持的产品版本

要查看支持 Fuse 7.11 的 JBoss EAP 的最新版本,请参阅 支持的配置 页面。

1.2. EAP 子系统上的 Camel

EAP 子系统中的 Camel 直接将 Apache Camel 集成到 JBoss EAP 容器中。在将 EAP 软件包的 Fuse 安装到 JBoss EAP 容器内后,此子系统可用。它为 Camel 部署提供了许多优势,包括简化 Camel 组件部署并与底层 JBoss EAP 容器集成。

红帽建议使用 Camel on EAP 子系统部署模型,以便在 JBoss EAP 上部署 Apache Camel 应用程序。

第 2 章 在 JBoss EAP 上构建应用程序

2.1. 概述

以下示例演示了在 EAP 上使用 camel-cdi 组件与红帽 Fuse 将 CDI Bean 与 Camel 路由集成。

在本例中,Camel 路由从 servlet HTTP GET 请求中获取消息有效负载,并将其传递到直接端点。然后,它会将有效负载传递到 Camel CDI Bean 调用,以生成消息响应并在 Web 浏览器页面中显示输出。

2.2. 运行项目

在运行项目之前,请确保您的设置包括 Maven 和红帽 Fuse 的应用服务器。

注意

如果使用 Java 17,则必须在启动应用程序前启用 JBoss EAP Elytron 子系统,方法是使用 JBoss EAP Elytron subsystem

  • 对于 Linux: ${JBOSS_HOME}/bin/jboss-cli.sh --file=docs/examples/enable-elytron-se17.cli -Dconfig=standalone-full.xml
  • 对于 Windows: %JBOSS_HOME%\bin\jboss-cli.bat --file=docss\enable-elytron-se17.cli -Dconfig=standalone-full.xml

执行以下步骤来运行项目:

  1. 以独立模式启动应用服务器:

    • 对于 Linux: ${JBOSS_HOME}/bin/standalone.sh -c standalone-full.xml
    • 对于 Windows: %JBOSS_HOME%\bin\standalone.bat -c standalone-full.xml
  2. 构建和部署项目: mvn install -Pdeploy
  3. 现在,浏览到 http://localhost:8080/example-camel-cdi/?name=World 位置。在网页上,以下消息 Hello World from 127.0.0.1 显示为输出。另外,您还可以在 MyRouteBuilder.java 类下查看 Camel Route,如下所示:
from("direct:start").bean("helloBean");

bean DSL 使 Camel 在 bean 注册表中查找名为 helloBean 的 bean。另外,由于 some Bean 类,bean 可供 Camel 使用。通过使用 @Named 注释,camel-cdi 会将 bean 添加到 Camel Bean 注册表。

@Named("helloBean")

public class SomeBean {

     public String someMethod(String name) throws Exception {

        return String.format("Hello %s from %s", name, InetAddress.getLocalHost().getHostAddress());

    }

}

如需更多信息,请参阅 $ EAP_HOME/quickstarts/camel/camel-cdi 目录。

2.3. 用于 JBoss EAP 的 BOM 文件

Maven Bill of Materials(BOM) 文件的目的是提供一组精心设计的 Maven 依赖项版本,从而为您保存每个 Maven 工件的版本,从而单独定义每个 Maven 工件的版本。

JBoss EAP 的 Fuse BOM 具有以下优点:

  • 定义 Maven 依赖项的版本,因此当您向 POM 添加依赖项时,您不需要指定版本。
  • 定义一组经过策展的依赖关系,这些依赖项是针对特定版本的 Fuse 完全测试和支持的。
  • 简化 Fuse 升级.
重要

红帽只支持由 Fuse BOM 定义的一组依赖项。

要将 BOM 文件合并到 Maven 项目中,请在项目的 pom.xml 文件中指定 dependencyManagement 元素(或者,在父 POM 文件中可能),如下例所示:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project ...>
  ...
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <!-- configure the versions you want to use here -->
    <fuse.version>7.11.1.fuse-sb2-7_11_1-00022-redhat-00002</fuse.version>

  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.jboss.redhat-fuse</groupId>
        <artifactId>fuse-eap-bom</artifactId>
        <version>${fuse.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  ...
</project>

在使用依赖关系管理机制指定 BOM 后,可以在不 指定工件版本的情况下,将 Maven 依赖项添加到 POM 中。例如,要为 camel-velocity 组件添加一个依赖项,您要将以下 XML 片段添加到 POM 中的 dependencies 元素中:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-velocity</artifactId>
  <scope>provided</scope>
</dependency>

注意 version 元素是如何从这个依赖关系定义中省略的。

第 3 章 功能

本章介绍了 Camel 关于 EAP 功能的必要信息。

Camel 上下文定义

Camel 上下文可以在 standalone-camel.xml 和 domain.xml 中进行配置,作为子系统定义的一部分,

<subsystem xmlns="urn:jboss:domain:camel:1.0">
   <camelContext id="system-context-1">
     <![CDATA[
     <route>
       <from uri="direct:start"/>
       <transform>
         <simple>Hello #{body}</simple>
       </transform>
     </route>
     ]]>
   </camelContext>
</subsystem>

Camel 上下文部署

您可以使用 -camel-context.xml 后缀将 camel 上下文部署到 JBoss EAP 中:

  • 独立 XML 文件
  • 另一个支持的部署的一部分

一个部署可以包含多个 -camel-context.xml 文件。

已部署的 Camel 上下文是 CDI 注入的,如下所示

@Resource(lookup = "java:jboss/camel/context/mycontext")
CamelContext camelContext;
[discrete]
### Management Console

默认情况下,对管理控制台的访问受到保护。因此,您需要先设置管理用户。

$ bin/add-user.sh

What type of user do you wish to add?
 a) Management User (mgmt-users.properties)
 b) Application User (application-users.properties)

Hawt.io 控制台应显示来自子系统配置的上下文。

hawtio camel 01

Arquillian 测试支持

EAP 测试套件上的 Camel 使用 WildFly Arquillian 受管容器。这可连接到已在运行的 JBoss EAP 实例,或者在需要时启动单机服务器实例。

实施了很多测试增强器,可让您在 EAP 特定类型上将这些 Camel 注入到您的 Arquillian 测试案例中。

@ArquillianResource
CamelContextFactory contextFactory;

@ArquillianResource
CamelContextRegistry contextRegistry;

第 4 章 配置

本章介绍了 Camel 子系统和部署配置的必要信息。

Camel 子系统配置

Camel 子系统配置可能包含静态系统路由。但是,系统会自动启动路由。

<subsystem xmlns="urn:jboss:domain:camel:1.0">
   <camelContext id="system-context-1">
     <![CDATA[
     <route>
       <from uri="direct:start"/>
       <transform>
         <simple>Hello #{body}</simple>
       </transform>
     </route>
     ]]>
   </camelContext>
</subsystem>

Camel 部署配置

如果要修改 Camel 部署默认配置,可以在部署中编辑 WEB-INF/jboss-all.xmlMETA-INF/jboss-all.xml 配置文件。

使用 jboss-all.xml 文件中的 <jboss-camel > XML 元素来控制 camel 配置。

禁用 Camel 子系统

如果您不想将 camel 子系统添加到部署中,请在 jboss-camel XML 元素上设置 enabled="false" 属性。

jboss-all.xml 文件示例:

<jboss umlns="urn:jboss:1.0">
  <jboss-camel xmlns="urn:jboss:jboss-camel:1.0" enabled="false"/>
</jboss>

选择组件

如果您添加嵌套的 & lt;component > 或 <component-module > XML 元素,而不是将默认 Camel 组件列表添加到部署中,则只有指定的组件才会添加到部署中。

jboss-all.xml 文件示例:

<jboss umlns="urn:jboss:1.0">
  <jboss-camel xmlns="urn:jboss:jboss-camel:1.0">
    <component name="camel-ftp"/>
    <component-module name="org.apache.camel.component.rss"/>
  </jboss-camel>
</jboss>

第 5 章 jakrkarta EE 集成

本章介绍了与 Jarkarta EE 集成点所需的信息。

5.1. CDI

Camel CDI 组件使用 CDI 作为依赖性注入框架,为 Apache Camel 提供自动配置。但是,它基于 convention-over-configuration。它实施标准的 camel bean 集成,以便您可以在 CDI Bean 中轻松使用 Camel 注解。

有关 CDI 的更多信息,请参阅 cdi 文档。

以下示例论述了如何通过路由来消耗和分配 Camel 上下文。

@Startup
@ApplicationScoped
@ContextName("cdi-context")
public class MyRouteBuilder extends RouteBuilder {

    @Override
    public void configure() throws Exception {
    	from("direct:start").transform(body().prepend("Hi"));
    }
}
@Inject
@ContextName("cdi-context")
private CamelContext camelctx;

5.1.1. 导入 XML DSL 配置

Camel CDI 集成允许您通过 @ImportResource 注释导入现有的 XML DSL 文件:

@ImportResource("camel-context.xml")
class MyBean {
}
注意

导入文件的位置必须存在于部署类路径中。将文件放在 WEB-INF 等位置无法正常工作。但是,WEB-INF/classes 将可以正常工作。

5.2. EJB

通过与 EJB3 子系统集成的 ejb 组件提供管理支持。

CamelContext camelctx = new DefaultCamelContext();
    camelctx.addRoutes(new RouteBuilder() {
        @Override
        public void configure() throws Exception {
            from("direct:start").to("ejb:java:module/HelloBean");
        }
    });

5.3. JAXB

JAXB 支持通过 Camel JAXB 数据格式

Camel 支持将 XML 数据解除到 JAXB 的类,以及从类到 XML 的总结.以下演示了使用 Camel JAXB 数据格式类进行汇总和解包的简单 Camel 路由。

5.3.1. JAXB Annotated 类

@XmlRootElement(name = "customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer implements Serializable {

    private String firstName;
    private String lastName;

    public Customer() {
    }

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

5.3.2. JAXB 类 XML 表示

<customer xmlns="http://org/wildfly/test/jaxb/model/Customer">
    <firstName>John</firstName>
    <lastName>Doe</lastName>
</customer>

5.3.3. Camel JAXB Unmarshalling

WildFlyCamelContext camelctx = contextFactory.createCamelContext(getClass().getClassLoader());

final JaxbDataFormat jaxb = new JaxbDataFormat();
jaxb.setContextPath("org.wildfly.camel.test.jaxb.model");

camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("direct:start")
        .unmarshal(jaxb);
    }
});
camelctx.start();

ProducerTemplate producer = camelctx.createProducerTemplate();

// Send an XML representation of the customer to the direct:start endpoint
Customer customer = producer.requestBody("direct:start", readCustomerXml(), Customer.class);
Assert.assertEquals("John", customer.getFirstName());
Assert.assertEquals("Doe", customer.getLastName());

5.3.4. Camel JAXB Marshalling

WildFlyCamelContext camelctx = contextFactory.createCamelContext();

final JaxbDataFormat jaxb = new JaxbDataFormat();
jaxb.setContextPath("org.wildfly.camel.test.jaxb.model");

camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("direct:start")
        .marshal(jaxb);
    }
});
camelctx.start();

ProducerTemplate producer = camelctx.createProducerTemplate();
Customer customer = new Customer("John", "Doe");
String customerXML = producer.requestBody("direct:start", customer, String.class);
Assert.assertEquals(readCustomerXml(), customerXML);

5.4. JAX-RS

JAX-RS 支持由 Camel CXF-RS 提供。

5.4.1. CXF-RS Producer

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <cxf:rsClient id="cxfProducer"
                  address="http://localhost:8080/rest"
                  serviceClass="org.wildfly.camel.examples.cxf.jaxrs.GreetingService" />

    <camelContext id="cxfrs-camel-context" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="direct:start" />
            <setHeader headerName="operationName">
                <simple>greet</simple>
            </setHeader>
            <setHeader headerName="CamelCxfRsUsingHttpAPI">
                <constant>false</constant>
            </setHeader>
            <to uri="cxfrs:bean:cxfProducer" />
        </route>
    </camelContext>
</beans>

5.4.2. CXF-RS Consumer

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <cxf:rsServer id="cxfConsumer"
                  address="http://localhost:8080/rest"
                  serviceClass="org.wildfly.camel.examples.cxf.jaxrs.GreetingService" />

    <camelContext id="cxfrs-camel-context" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="cxfrs:bean:cxfConsumer" />
            <setBody>
                <constant>Hello world</constant>
            </setBody>
        </route>
    </camelContext>
</beans>

5.4.3. 使用 Camel REST DSL 的 JAX-RS Consumer

Camel REST DSL 提供了编写充当 JAX-RS 消费者的 Camel 路由的功能。以下 RouteBuilder 类显示如下:

@Startup
@ApplicationScoped
@ContextName("rest-camel-context")
public class RestConsumerRouteBuilder extends RouteBuilder {
  @Override
  public void configure() throws Exception {

    // Use the camel-undertow component to provide REST integration
    restConfiguration().component("undertow")
      .contextPath("/rest").port(8080).bindingMode(RestBindingMode.json);

    rest("/customer")
      // GET /rest/customer
      .get()
        .produces(MediaType.APPLICATION_JSON)
        .to("direct:getCustomers")
      // GET /rest/customer/1
      .get("/{id}")
        .produces(MediaType.APPLICATION_JSON)
        .to("direct:getCustomer")
      // POST /rest/customer
      .post()
        .type(Customer.class)
        .to("direct:createCustomer");
      // PUT /rest/customer
      .put()
        .type(Customer.class)
        .to("direct:updateCustomer");
      // DELETE /rest/customer/1
      .delete("/{id}")
        .to("direct:deleteCustomer");
  }
}

通过设置绑定模式,Camel canmarshal 和 unmarshal JSON 数据可以通过指定 'produces()' 或 'type()' 配置步骤。

注意
  • REST DSL 配置从 restConfiguration().component("undertow") 开始。
  • EAP 子系统上的 Camel 仅支持 camel-servlet 和 camel-undertow 组件,以用于 REST DSL。但是,如果您配置其他组件,它将无法正常工作。

5.4.4. 安全性

请参阅 JAX-RS 安全性部分

5.4.5. EAP 上的 Fuse 中的 Quickstart 示例

在快速入门 /camel/camel-cxf-jaxrs 目录的 Fuse 中提供了快速入门 示例。

5.5. JAX-WS

WebService 支持通过 CXF 组件提供,该组件与使用 Apache CXF 的 JBoss EAP WebServices 子系统集成。

5.5.1. JAX-WS CXF Producer

以下代码示例使用 CXF 来消耗已由 WildFly Web 服务子系统部署的 Web 服务

5.5.1.1. JAX-WS Web 服务

以下简单的 Web 服务具有一个简单的"greet"方法,它将串联两个字符串参数并返回它们。

当 JBoss EAP Web 服务子系统检测到包含 JAX-WS 注释的类时,它会引导 CXF 端点。在本例中,服务端点将位于 http://hostname:port/context-root/greeting

// Service interface
@WebService(name = "greeting")
public interface GreetingService {
    @WebMethod(operationName = "greet", action = "urn:greet")
    String greet(@WebParam(name = "message") String message, @WebParam(name = "name") String name);
}

// Service implementation
public class GreetingServiceImpl implements GreetingService{
    public String greet(String message, String name) {
        return message + " " + name ;
    }
}

5.5.1.2. Camel 路由配置

此 RouteBuilder 配置 CXF producer 端点,它将使用上面定义的"问候语"Web 服务。CDI 与 camel-cdi 组件结合使用,用于引导 RouteBuilder 和 CamelContext。

@Startup
@ApplicationScoped
@ContextName("cxf-camel-context")
public class CxfRouteBuilder extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("direct:start")
        .to("cxf://http://localhost:8080/example-camel-cxf/greeting?serviceClass=" + GreetingService.class.getName());
    }
}

问候 Web 服务"greet"需要两个参数。它们可以通过 ProducerTemplate 方式提供给上述路由。Web 服务方法参数值通过构造对象数组来配置,该数组作为交换正文传递。

String message = "Hello"
String name = "Kermit"

ProducerTemplate producer = camelContext.createProducerTemplate();
Object[] serviceParams = new Object[] {message, name};
String result = producer.requestBody("direct:start", serviceParams, String.class);

5.5.2. Camel CXF JAX-WS Consumer

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://camel.apache.org/schema/cxf"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <cxf:cxfEndpoint id="cxfConsumer"
                     address="http://localhost:8080/webservices/greeting"
                     serviceClass="org.wildfly.camel.examples.cxf.jaxws.GreetingService" />

    <camelContext id="cxfws-camel-context" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="cxf:bean:cxfConsumer" />
            <to uri="log:ws" />
        </route>
    </camelContext>

</beans>

5.5.3. 安全性

请参阅 JAX-WS 安全性部分

5.5.4. EAP 上的 Fuse 中的 Quickstart 示例

在快速入门 /camel/camel-cxf-jaxws 目录的 Fuse 中提供了快速入门 示例。

5.6. JMS

消息传递支持通过 JMS 组件提供,它们与 JBoss EAP Messaging(ActiveMQintroduction)子系统集成。

通过配置特定于供应商的资源适配器或不可用(如果使用 JBoss 通用 JMS 资源适配器),可以与其他 JMS 实现集成。

5.6.1. JBoss EAP JMS 配置

您可以通过标准的 JBoss EAP XML 配置文件配置 JBoss EAP 消息传递子系统。https://docs.jboss.org/author/display/WFLY8/Messaging+configuration例如: standalone.xml 或 domain.xml。

例如,之后您在内存实例中使用嵌入的 ActiveMQ Artemis。您首先,通过将以下 XML 配置添加到jms-destinations 部分,在 messaging 子系统上配置新的 JMS 队列。

<jms-queue name="WildFlyCamelQueue">
  <entry name="java:/jms/queue/WildFlyCamelQueue"/>
</jms-queue>

或者您可以使用 CLI 脚本添加队列。

$ jms-queue add --queue-address=WildFlyCamelQueue --entries=queue/WildFlyCamelQueue,java:/jms/queue/WildFlyCamelQueue

另外,您还可以在自定义 jms.xml 部署描述符中创建消息传递 部署配置。如需更多信息,请参阅 JBoss EAP messaging 子系统文档中的部署 -jms.xml 文件部分。

5.6.2. Camel 路由配置

以下 JMS producer 和使用者示例利用 JBoss EAP 嵌入式 ActiveMQ Artemis 服务器发布和使用消息到目的地。

示例还将 CDI 与 camel-cdi 组件结合使用。JMS ConnectionFactory 实例通过 JNDI 查找注入到 Camel RouteBuilder 中。

5.6.2.1. JMS Producer

DefaultJMSConnectionFactory 连接工厂从 JNDI 注入到 RouteBuilder 中。在 JBoss EAP XML 配置下,您可以在 messaging 子系统内找到连接工厂。

接下来,计时器端点每 10 秒运行一次,以将 XML 有效负载发送到之前配置的 WildFlyCamelQueue 目标。

@Startup
@ApplicationScoped
@ContextName("jms-camel-context")
public class JmsRouteBuilder extends RouteBuilder {

  @Resource(mappedName = "java:jboss/DefaultJMSConnectionFactory")
  private ConnectionFactory connectionFactory;

  @Override
  public void configure() throws Exception {
    JmsComponent component = new JmsComponent();
    component.setConnectionFactory(connectionFactory);

    getContext().addComponent("jms", component);

    from("timer://sendJMSMessage?fixedRate=true&period=10000")
    .transform(constant("<?xml version='1.0><message><greeting>hello world</greeting></message>"))
    .to("jms:queue:WildFlyCamelQueue")
    .log("JMS Message sent");
  }
}

每次将 JMS 消息添加到 WildFlyCamelQueue 目的地时,都将向控制台输出日志消息。要验证消息是否放置在队列上,您可以使用 JBoss EAP 管理控制台。

JMS 队列浏览

5.6.2.2. JMS Consumer

要使用 JMS 消息,Camel RouteBuilder 实施与制作者示例类似。

如前文所述,连接工厂从 JNDI 发现,并注入了 JMSComponent 实例。

当 JMS 端点消耗来自 WildFlyCamelQueue 目的地的消息时,内容将记录到控制台。

@Override
public void configure() throws Exception {
  JmsComponent component = new JmsComponent();
  component.setConnectionFactory(connectionFactory);

  getContext().addComponent("jms", component);

  from("jms:queue:WildFlyCamelQueue")
  .to("log:jms?showAll=true");
}

5.6.2.3. JMS 事务

为了使 Camel JMS 路由能够参与 JMS 事务,需要使用一些额外的配置。由于 camel-jms 围绕 spring-jms 构建,因此您需要配置一些 Spring 类,使其能与 JBoss EAP 的事务管理器和连接工厂一起工作。以下代码示例演示了如何使用 CDI 配置事务性 JMS Camel 路由。

camel-jms 组件需要类型为 org.springframework.transaction.PlatformTransactionManager 的事务管理器。因此,您首先创建一个扩展 JtaTransactionManager。请注意,an 标注了 @Named,以便 bean 在 Camel Bean 注册表中注册。另请注意,JBoss EAP 事务管理器和用户事务实例使用 CDI 注入。

@Named("transactionManager")
public class CdiTransactionManager extends JtaTransactionManager {

  @Resource(mappedName = "java:/TransactionManager")
  private TransactionManager transactionManager;

  @Resource
  private UserTransaction userTransaction;

  @PostConstruct
  public void initTransactionManager() {
    setTransactionManager(transactionManager);
    setUserTransaction(userTransaction);
  }
}

接下来,您需要声明要使用的事务策略。再次使用 @Named 注释,使 bean 可供 Camel 使用。事务管理器也注入,以便可使用所需的事务策略创建 TransactionTemplate。本例中为 PROPAGATION_REQUIRED。

@Named("PROPAGATION_REQUIRED")
public class CdiRequiredPolicy extends SpringTransactionPolicy {
  @Inject
  public CdiRequiredPolicy(CdiTransactionManager cdiTransactionManager) {
    super(new TransactionTemplate(cdiTransactionManager,
      new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)));
  }
}

现在,您可以配置 Camel RouteBuilder 类,并注入 Camel JMS 组件所需的依赖项。JBoss EAP XA 连接工厂与之前配置的事务管理器一起注入。

在本示例 RouteBuilder 中,每当来自 queue1 的消息被使用时,它们都会路由到名为 queue2 的其他 JMS 队列。来自 queue2 的消息会使用 rollback()DSL 方法回滚 JMS 事务。这将导致原始消息放置在死信队列(DLQ)上。

@Startup
@ApplicationScoped
@ContextName("jms-camel-context")
public class JMSRouteBuilder extends RouteBuilder {

  @Resource(mappedName = "java:/JmsXA")
  private ConnectionFactory connectionFactory;

  @Inject
  CdiTransactionManager transactionManager;

  @Override
  public void configure() throws Exception {
    // Creates a JMS component which supports transactions
    JmsComponent jmsComponent = JmsComponent.jmsComponentTransacted(connectionFactory, transactionManager);
    getContext().addComponent("jms", jmsComponent);

    from("jms:queue:queue1")
      .transacted("PROPAGATION_REQUIRED")
      .to("jms:queue:queue2");

    // Force the transaction to roll back. The message will end up on the Wildfly 'DLQ' message queue
    from("jms:queue:queue2")
      .to("log:end")
      .rollback();
  }

5.6.2.4. 远程 JMS 目的地

个 JBoss EAP 实例可以通过 远程 JNDI 将消息发送到另一 JBoss EAP 实例上配置的消息。

需要额外的 JBoss EAP 配置才能实现这一点。首先配置导出的 JMS 队列。

只有 java:jboss/exported 命名空间中的 JNDI 名称才会被视为远程客户端的候选者,因此队列会被适当地命名。

注意

您必须在 JBoss EAP 客户端 应用服务器和JBoss EAP 远程服务器上配置队列。

<jms-queue name="RemoteQueue">
  <entry name="java:jboss/exported/jms/queues/RemoteQueue"/>
</jms-queue>

在客户端可以连接到远程服务器前,需要配置用户访问凭证。在远程服务器中运行 add user 实用程序在 "guest"组中创建新应用用户。这个示例的用户名为 'admin' 且密码为 'secret'。

RouteBuilder 实施与上例不同。您需要配置 InitialContext 并从 JNDI 中检索它,而不是注入连接工厂。

configureInitialContext 方法创建了这个 InitialContext。请注意,您需要设置提供程序 URL,该 URL 应引用您的远程 JBoss EAP 实例主机名和端口号。本示例使用 JBoss EAP JMS http-connector,但 此处列出了 alternatives。

最后,路由配置为每 10 秒发送一次 XML 有效负载到之前配置的远程目的地 - 'RemoteQueue'。

@Override
public void configure() throws Exception {
  Context initialContext = configureInitialContext();
  ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup("java:jms/RemoteConnectionFactory");

  JmsComponent component = new JmsComponent();
  component.setConnectionFactory(connectionFactory);

  getContext().addComponent("jms", component);

  from("timer://foo?fixedRate=true&period=10000")
  .transform(constant("<?xml version='1.0><message><greeting>hello world</greeting></message>"))
  .to("jms:queue:RemoteQueue?username=admin&password=secret")
  .to("log:jms?showAll=true");
}

private Context configureInitialContext() throws NamingException {
  final Properties env = new Properties();
  env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
  env.put(Context.PROVIDER_URL, System.getProperty(Context.PROVIDER_URL, "http-remoting://my-remote-host:8080"));
  env.put(Context.SECURITY_PRINCIPAL, System.getProperty("username", "admin"));
  env.put(Context.SECURITY_CREDENTIALS, System.getProperty("password", "secret"));
  return new InitialContext(env);
}

5.6.3. 安全性

请参阅 JMS 安全部分

5.6.4. EAP 上的 Fuse 中的 Quickstart 示例

快速入门/camel/camel-jms 目录中,您的 Fuse 中提供了 EAP 安装的快速入门示例。

5.7. JMX

您可以通过与 JBoss EAP JMX 子系统集成的 JMX 组件提供管理支持。

CamelContext camelctx = contextFactory.createWildflyCamelContext(getClass().getClassLoader());
camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        String host = InetAddress.getLocalHost().getHostName();
        from("jmx:platform?format=raw&objectDomain=org.apache.camel&key.context=" + host + "/system-context-1&key.type=routes&key.name=\"route1\"" +
        "&monitorType=counter&observedAttribute=ExchangesTotal&granularityPeriod=500").
        to("direct:end");
    }
});
camelctx.start();

ConsumerTemplate consumer = camelctx.createConsumerTemplate();
MonitorNotification notifcation = consumer.receiveBody("direct:end", MonitorNotification.class);
Assert.assertEquals("ExchangesTotal", notifcation.getObservedAttribute());

5.8. JNDI

JNDI 集成由 JBoss EAP 特定的 CamelContext 提供,如下所示:

InitialContext inictx = new InitialContext();
CamelContextFactory factory = inictx.lookup("java:jboss/camel/CamelContextFactory");
WildFlyCamelContext camelctx = factory.createCamelContext();

WildFlyCamelContext 中,您可以获取预配置的命名上下文

Context context = camelctx.getNamingContext();
context.bind("helloBean", new HelloBean());

然后可从 Camel 路由中引用该路由。

camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("direct:start").beanRef("helloBean");
    }
});
camelctx.start();

5.9. JPA

JPA 集成由 Camel JPA 组件 提供。您可以通过提供 persistence.xml 配置文件和一些 JPA 所标注的类来开发 Camel JPA 应用程序。

5.9.1. persistence.xml 示例

在以下示例中,您可以使用 JBoss EAP 内存中 ExampleDS 数据源(在 JBoss EAP standalone.xml 配置文件中配置)。

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="camel">
        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
        <class>org.wildfly.camel.test.jpa.model.Customer</class>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>

</persistence>

5.9.2. JPA entitiy 示例

@Entity
@Table(name = "customer")
public class Customer implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private String firstName;
    private String lastName;

    public Customer() {
    }

    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

5.9.3. Camel JPA 端点/路由配置

配置了 JPA,您可以使用 CDI 将 EntityManager 和 UserTransaction 实例注入到 RouteBuilder 类或测试问题单中:

@PersistenceContext
EntityManager em;

@Inject
UserTransaction userTransaction;

现在配置 Camel 路由和 JPA 端点:

WildFlyCamelContext camelctx = contextFactory.createCamelContext(getClass().getClassLoader());

EntityManagerFactory entityManagerFactory = em.getEntityManagerFactory();

// Configure a transaction manager
JtaTransactionManager transactionManager = new JtaTransactionManager();
transactionManager.setUserTransaction(userTransaction);
transactionManager.afterPropertiesSet();

// Configure the JPA endpoint to use the correct EntityManagerFactory and JtaTransactionManager
final JpaEndpoint jpaEndpoint = new JpaEndpoint();
jpaEndpoint.setCamelContext(camelctx);
jpaEndpoint.setEntityType(Customer.class);
jpaEndpoint.setEntityManagerFactory(entityManagerFactory);
jpaEndpoint.setTransactionManager(transactionManager);

camelctx.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
    from("direct:start")
    .to(jpaEndpoint);
}
});

camelctx.start();

最后,您可以将"Customer"实体发送到"direct:start"端点,然后查询 ExampleDS 数据源以验证已保存了记录。

Customer customer = new Customer("John", "Doe");
ProducerTemplate producer = camelctx.createProducerTemplate();
producer.sendBody("direct:start", customer);

// Query the in memory database customer table to verify that a record was saved
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
query.select(criteriaBuilder.count(query.from(Customer.class)));

long recordCount = em.createQuery(query).getSingleResult();

Assert.assertEquals(1L, recordCount);

第 6 章 Camel 组件

本章详细介绍了支持的 camel 组件信息

6.1. camel-activemq

Camel ActiveMQ 集成由 activemq 组件提供。

组件可以配置为处理嵌入式或外部代理。对于 Wildfly / EAP 容器管理的连接池和 XA-Transaction 支持,可以将 ActiveMQ 资源适配器 配置为容器配置文件。

6.1.1. JBoss EAP ActiveMQ 资源适配器配置

下载 ActiveMQ 资源适配器 rar 文件。以下步骤概述了如何配置 ActiveMQ 资源适配器。

  1. 停止您的 JBoss EAP 实例。
  2. 下载资源适配器并将 复制到相关的 JBoss EAP 部署目录。对于独立模式:

    cp activemq-rar-5.11.1.rar ${JBOSS_HOME}/standalone/deployments/activemq-rar.rar
  3. 为 ActiveMQ 适配器配置 JBoss EAP 资源适配器子系统。
<subsystem xmlns="urn:jboss:domain:resource-adapters:2.0">
     <resource-adapters>
         <resource-adapter id="activemq-rar.rar">
             <archive>
                 activemq-rar.rar
             </archive>
             <transaction-support>XATransaction</transaction-support>
             <config-property name="UseInboundSession">
                 false
             </config-property>
             <config-property name="Password">
                 defaultPassword
             </config-property>
             <config-property name="UserName">
                 defaultUser
             </config-property>
             <config-property name="ServerUrl">
                 tcp://localhost:61616?jms.rmIdFromConnectionId=true
             </config-property>
             <connection-definitions>
                 <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/ActiveMQConnectionFactory" enabled="true" pool-name="ConnectionFactory">
                     <xa-pool>
                         <min-pool-size>1</min-pool-size>
                         <max-pool-size>20</max-pool-size>
                         <prefill>false</prefill>
                         <is-same-rm-override>false</is-same-rm-override>
                     </xa-pool>
                 </connection-definition>
             </connection-definitions>
             <admin-objects>
                 <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:/queue/HELLOWORLDMDBQueue" use-java-context="true" pool-name="HELLOWORLDMDBQueue">
                     <config-property name="PhysicalName">
                         HELLOWORLDMDBQueue
                     </config-property>
                 </admin-object>
                 <admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:/topic/HELLOWORLDMDBTopic" use-java-context="true" pool-name="HELLOWORLDMDBTopic">
                     <config-property name="PhysicalName">
                         HELLOWORLDMDBTopic
                     </config-property>
                 </admin-object>
             </admin-objects>
         </resource-adapter>
     </resource-adapters>
 </subsystem>

如果您的资源适配器存档文件名与 located-rar.rar 不同,您必须更改上述配置中 archive 元素的内容以匹配存档文件的名称。

必须选择 UserName 和 Password 配置属性的值以匹配外部代理中有效用户的凭证。

您可能需要更改 ServerUrl 配置属性的值,以匹配外部代理公开的实际主机名和端口。

4) 启动 JBoss EAP。如果一切配置正确,您应该可以看到 JBoss EAP server.log 中的消息,如下所示:

13:16:08,412 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-5) JBAS010406: Registered connection factory java:/AMQConnectionFactory`

6.1.2. Camel 路由配置

以下 ActiveMQ producer 和使用者示例利用 ActiveMQ 嵌入式代理和"vm' 传输(避免对外部 ActiveMQ 代理的需求)。

示例将 CDI 与 camel-cdi 组件结合使用。JMS ConnectionFactory 实例通过 JNDI 查找注入到 Camel RouteBuilder 中。

6.1.2.1. ActiveMQ Producer

@Startup
@ApplicationScoped
@ContextName("activemq-camel-context")
public class ActiveMQRouteBuilder extends RouteBuilder {

  @Override
  public void configure() throws Exception {
    from("timer://sendJMSMessage?fixedRate=true&period=10000")
    .transform(constant("<?xml version='1.0><message><greeting>hello world</greeting></message>"))
    .to("activemq:queue:WildFlyCamelQueue?brokerURL=vm://localhost")
    .log("JMS Message sent");
  }
}

每次将消息添加到 WildFlyCamelQueue 目的地时,都将向控制台输出日志消息。要验证消息实际上是否已放置到队列中,您可以使用由 Camel on EAP 子系统提供的 ../features/hawtio.md[Hawtio 控制台、window=_THREE]。

ActiveMQ 队列浏览

6.1.2.2. ActiveMQ Consumer

若要利用 ActiveMQ 消息,Camel RouteBuilder 实施与制作者示例类似。

当 ActiveMQ 端点消耗来自 WildFlyCamelQueue 目的地的消息时,内容将记录到控制台。

@Override
public void configure() throws Exception {
  from("activemq:queue:WildFlyCamelQueue?brokerURL=vm://localhost")
  .to("log:jms?showAll=true");
}

6.1.2.3. ActiveMQ 事务

6.1.2.3.1. ActiveMQ 资源适配器配置

需要 ActiveMQ 资源适配器以利用 XA 事务支持、连接池等。

以下 XML 片段演示了如何在 JBoss EAP 服务器 XML 配置中配置资源适配器。请注意 ,serverURL 设置为使用嵌入式代理。连接工厂与 JNDI 名称 java:/ActiveMQConnectionFactory 绑定。这将在 RouteBuilder 示例中查找。

最后,两个队列配置为名为 'queue1' 和 'queue2'。

<subsystem xmlns="urn:jboss:domain:resource-adapters:2.0">
  <resource-adapters>
    <resource-adapter id="activemq-rar.rar">
      ...
      <admin-objects>
        <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:/queue/queue1" use-java-context="true" pool-name="queue1pool">
          <config-property name="PhysicalName">queue1</config-property>
        </admin-object>
        <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:/queue/queue2" use-java-context="true" pool-name="queue2pool">
          <config-property name="PhysicalName">queue2</config-property>
        </admin-object>
      </admin-objects>
    </resource-adapter>
  </resource-adapters>
</subsystem>

6.1.2.4. 事务管理器

camel-activemq 组件需要类型为 org.springframework.transaction.PlatformTransactionManager 的事务管理器。因此,您可以首先创建一个满足此要求的 bean 扩展 JtaTransactionManager。请注意,an 标注了 @Named,以便 bean 在 Camel Bean 注册表中注册。另请注意,JBoss EAP 事务管理器和用户事务实例使用 CDI 注入。

@Named("transactionManager")
public class CdiTransactionManager extends JtaTransactionManager {

  @Resource(mappedName = "java:/TransactionManager")
  private TransactionManager transactionManager;

  @Resource
  private UserTransaction userTransaction;

  @PostConstruct
  public void initTransactionManager() {
    setTransactionManager(transactionManager);
    setUserTransaction(userTransaction);
  }
}

6.1.2.5. 事务策略

接下来,您需要声明要使用的事务策略。再次使用 @Named 注释,使 bean 可供 Camel 使用。事务管理器也注入,以便可使用所需的事务策略创建 TransactionTemplate。本例中为 PROPAGATION_REQUIRED

@Named("PROPAGATION_REQUIRED")
public class CdiRequiredPolicy extends SpringTransactionPolicy {
  @Inject
  public CdiRequiredPolicy(CdiTransactionManager cdiTransactionManager) {
    super(new TransactionTemplate(cdiTransactionManager,
      new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED)));
  }
}

6.1.2.6. 路由构建器

现在,您可以配置 Camel RouteBuilder 类,并注入 Camel ActiveMQ 组件所需的依赖项。您在资源适配器配置上配置的 ActiveMQ 连接工厂会与您之前配置的事务管理器一起注入。

在本示例 RouteBuilder 中,每当来自 queue1 的消息被使用时,它们都会路由到名为 queue2 的其他 JMS 队列。来自 queue2 的消息会使用 rollback()DSL 方法回滚 JMS 事务。这将导致原始消息放置在死信队列(DLQ)上。

@Startup
@ApplicationScoped
@ContextName("activemq-camel-context")
public class ActiveMQRouteBuilder extends RouteBuilder {

  @Resource(mappedName = "java:/ActiveMQConnectionFactory")
  private ConnectionFactory connectionFactory;

  @Inject
  private CdiTransactionManager transactionManager;

  @Override
  public void configure() throws Exception {
    ActiveMQComponent activeMQComponent = ActiveMQComponent.activeMQComponent();
    activeMQComponent.setTransacted(false);
    activeMQComponent.setConnectionFactory(connectionFactory);
    activeMQComponent.setTransactionManager(transactionManager);

    getContext().addComponent("activemq", activeMQComponent);

      errorHandler(deadLetterChannel("activemq:queue:ActiveMQ.DLQ")
      .useOriginalMessage()
      .maximumRedeliveries(0)
      .redeliveryDelay(1000));

    from("activemq:queue:queue1F")
      .transacted("PROPAGATION_REQUIRED")
      .to("activemq:queue:queue2");

    from("activemq:queue:queue2")
      .to("log:end")
      .rollback();
  }
}

6.1.3. 安全性

请参阅 JMS 安全部分

6.1.4. GitHub 上的代码示例

GitHub 上提供了 camel-activemq 应用程序 的示例。

6.2. camel-jms

有两种支持的方法将 camel-jms、camel-sjms 和 camel-sjms2 端点连接到远程 AMQ 7 代理。

  1. 使用 pooled-connection-factory 配置远程连接器,如"JBoss EAP 配置消息传递指南》中的"配置" Resource Adapter to Connect to Red Hat JBoss AMQ 7 一节中所述。
  2. 使用 connection-factory 配置远程连接器,如 使用 connection-factory 配置远程连接器

第一个选项是首选的方法,因为它提供连接池和 XA 事务支持。

对于使用持久订阅者的消息传递场景,由于 JavaEE 7 规格所施加的限制,JBoss EAP 上的 Fuse 7.11 不支持 pooled-connection-factory。在这种情况下,最好配置标准未池连接。

使用 connection-factory 配置远程连接器

  1. 创建一个指向远程消息传递服务器的出站套接字绑定:

    /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=messaging-remote-throughput:add(host=localhost, port=61616)
  2. 创建引用在第 1 步中创建的出站套接字绑定的远程连接器。

    /subsystem=messaging-activemq/server=default/remote-connector=netty-remote-throughput:add(socket-binding=messaging-remote-throughput)
  3. 创建连接因素,引用第 2 步中创建的远程连接器。

    /subsystem=messaging-activemq/server=default/connection-factory=simple-remote-artemis-connection-factory:add(entries=[java:/jms/RemoteJms],connectors=[netty-remote-throughput])

6.2.1. 消息传递代理和客户端

摘要

Fuse 7.11 不提供默认的内部消息传递代理,但它旨在与外部 JMS 代理进行接口。

JBoss EAP 上的 Fuse 7.11 使用在 JBoss EAP 上配置消息传递 代理时详述的资源适配器。

有关 JBoss EAP 上 Fuse 7.11 上可用的外部代理、JCA 适配器和 Camel 组件组合的更多信息,请参阅支持的配置。https://access.redhat.com/articles/310603

有关使用 JMS 的 JBoss EAP 上 Fuse 连接到外部代理的更多信息,请参阅 第 6.2 节 “camel-jms”

Camel-jms Quickstart

提供了快速入门,以演示在 JBoss EAP 上使用 Fuse 来制作和使用 JMS 消息的 camel-jms 组件。

在此快速入门中,Camel 路由会使用来自 EAP_HOME/standalone/data/orders 的文件,并将其内容放在名为 OrdersQueue 的内存中 ActiveMQ root 队列上。然后,另一个 Camel 路由消耗 OrdersQueue 的内容,并将订单排序为 EAP_HOME/standalone/data/orders/processed 中的各个国家目录。

CLI 命令创建和删除 OrdersQueue CLI 脚本,以便在部署应用和取消部署时为您创建并移除 JMS OrdersQueue。这些脚本位于 EAP_HOME/quickstarts/camel-jms/src/main/resources/cli 目录中。

先决条件

要运行此快速入门,您必须有一个 Fuse 7.11 工作版本

您还需遵循 使用 JBoss AMQ 进行远程 JMS 通信 中的说明,以连接到外部 AMQ 7 代理。然后您可以使用默认连接工厂注入连接工厂。

@Resource(mappedName = "java:jboss/RemoteJmsXA")
ConnectionFactory connectionFactory;

设置快速入门

  1. 以单机模式启动 JBOSS EAP。
  2. 导航到 EAP_HOME/quickstarts/camel/camel-jms
  3. 输入 mvn clean install -Pdeploy' 以构建和部署 Quickstart。
  4. 浏览至 http://localhost:8080/example-camel-jms

您应该会看到一个名为"Orders Received"的页面。随着向示例应用程序发送订单,在此页中将列出每个国家每个国家的订单列表。

运行快速入门

EAP_HOME/quickstarts/camel-jms/src/main/resources 目录中有一些示例顺序 XML 文件。Camel 将每 5 秒随机选择一个文件,并将其复制到 EAP_HOME/standalone/data/orders 中进行处理。

控制台将输出信息详细描述了每个订购所发生的情况。输出将如下所示:

JmsConsumer[OrdersQueue]) Sending order to the UK
JmsConsumer[OrdersQueue]) Sending order to another country
JmsConsumer[OrdersQueue]) Sending order to the US

当文件被使用后,您可以返回到 http://localhost:8080/example-camel-jms/orders。每个国家的接收订单的数目应该已由 1 增加。

所有处理的订购将分成以下目的地:

EAP_HOME/standalone/data/orders/processed/uk
EAP_HOME/standalone/data/orders/processed/us
EAP_HOME/standalone/data/orders/processed/other

取消部署

要取消部署示例,可导航到 EAP_HOME/quickstarts/camel/camel-jms run mvn clean -Pdeploy

6.3. camel-mail

与电子邮件的交互由 邮件 组件提供。

默认情况下,Camel 将创建自己的邮件会话,并使用它来与您的邮件服务器进行交互。由于 JBoss EAP 已经为安全连接、用户名和密码加密提供所有相关支持,因此建议在 JBoss EAP 配置中配置您的邮件会话,并使用 JNDI 将它们连接到您的 Camel 端点。

6.3.1. JBoss EAP 配置

首先,您为 Mail 服务器配置 JBoss EAP 邮件子系统。以下示例添加了 Google 邮件 IMAP 和 SMTP 的配置。

在"默认"会话后配置一个 mail-session。

<subsystem xmlns="urn:jboss:domain:mail:2.0">
    <mail-session name="default" jndi-name="java:jboss/mail/Default">
      <smtp-server outbound-socket-binding-ref="mail-smtp"/>
    </mail-session>
    <mail-session debug="true" name="gmail" jndi-name="java:jboss/mail/gmail">
      <smtp-server outbound-socket-binding-ref="mail-gmail-smtp" ssl="true" username="your-username-here" password="your-password-here"/>
      <imap-server outbound-socket-binding-ref="mail-gmail-imap" ssl="true" username="your-username-here" password="your-password-here"/>
    </mail-session>
</subsystem>

您可以配置 'mail-gmail-smtp' 和 'mail-gmail-imap' 的 outbound-socket-binding-ref 值。

下一步是配置这些套接字绑定。您可以按照以下方法在 socket-binding-group 配置中添加额外的绑定。

<outbound-socket-binding name="mail-gmail-smtp">
  <remote-destination host="smtp.gmail.com" port="465"/>
</outbound-socket-binding>

<outbound-socket-binding name="mail-gmail-imap">
  <remote-destination host="imap.gmail.com" port="993"/>
</outbound-socket-binding>

这会将邮件会话配置为连接到端口 465 和 192.168.0.3 上的端口 465.gmail.com 上的 host smtp.gmail.com。如果您使用不同的邮件主机,则此详细信息会有所不同。

6.3.2. POP3 配置

如果您需要配置 POP3 会话,则与以上示例中定义的原则相同。

<!-- Server configuration -->
<pop3-server outbound-socket-binding-ref="mail-pop3" ssl="true" username="your-username-here" password="your-password-here"/>

<!-- Socket binding configuration -->
<outbound-socket-binding name="mail-gmail-imap">
  <remote-destination host="pop3.gmail.com" port="993"/>
</outbound-socket-binding>

6.3.3. Camel 路由配置

6.3.3.1. mail producer

这个示例使用 SMTPS 协议和 CDI 与 camel-cdi 组件一起。您在 JBoss EAP 配置中配置的 Java 邮件会话通过 JNDI 注入到 Camel RouteBuilder 中。

6.3.3.1.1. 路由构建器 SMTP 示例

GMail 邮件会话使用 @Resource 注释注入 Producer 类,并引用您之前配置的 jndi-name 属性。这可让您在 camel-mail 端点配置中引用邮件会话。

public class MailSessionProducer {
    @Resource(lookup = "java:jboss/mail/greenmail")
    private Session mailSession;

    @Produces
    @Named
    public Session getMailSession() {
        return mailSession;
    }
}
public class MailRouteBuilder extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        from("direct:start")
        .to("smtps://smtp.gmail.com?session=#mailSession");
    }
}

要发送电子邮件,您可以创建一个 ProducerTemplate,并将适当的正文与必要的电子邮件标头一起发送。

Map<String, Object> headers = new HashMap<String, Object>();
headers.put("To", "destination@test.com");
headers.put("From", "sender@example.com");
headers.put("Subject", "Camel on Wildfly rocks");

String body = "Hi,\n\nCamel on Wildfly rocks!.";

ProducerTemplate template = camelContext.createProducerTemplate();
template.sendBodyAndHeaders("direct:start", body, headers);

6.3.3.2. 邮件消费者

要接收电子邮件,您可以使用 IMAP 邮件端点。Camel 路由配置如下所示:

public void configure() throws Exception {
   from("imaps://imap.gmail.com?session=#mailSession")
   .to("log:email");
}

6.3.4. 安全性

6.3.4.1. SSL 配置

JBoss EAP 可以配置为管理 Java 邮件会话,以及使用 SSL / TLS 管理它们的相关传输。在配置邮件会话时,您可以在服务器类型上配置 SSL 或 TLS:

  • smtp-server
  • imap-server
  • pop-server

通过设置属性 ssl="true"tls="true"

6.3.4.2. 保护密码

建议您不要对配置文件中的密码使用明文。您可以使用 WildFly Vault 屏蔽敏感数据。

6.3.4.3. Camel 安全

Camel 端点安全文档可在 邮件 组件指南中找到。Camel 还有一个 安全概述页面

6.3.5. GitHub 上的代码示例

GitHub 上提供了 camel-mail 应用程序示例,供您尝试发送/接收电子邮件。

6.4. camel-rest

其它组件允许您使用 Rest DSL 和作为 REST 传输其他 Camel 组件来定义 REST 端点。http://camel.apache.org/rest.html

注意

EAP 子系统上的 Camel 仅支持 camel-servlet 和 camel-undertow 组件,以用于 REST DSL。但是,如果您尝试配置其他组件,子系统不起作用。

CamelContext camelctx = new DefaultCamelContext();
camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        restConfiguration().component("servlet").contextPath("camel/rest").port(8080);
        rest("/hello").get("/{name}").to("direct:hello");
        from("direct:hello").transform(simple("Hello ${header.name}"));
    }
});

6.5. camel-rest-swagger

rest-swagger 组件可以从 Swagger 文档配置 REST 制作者,并委派给实施 RestProducer onnectionFactoryy 接口的组件,例如:

6.6. camel-sql

SQL 组件允许您使用 JDBC 查询来处理数据库。此组件和 JDBC 组件之间的区别是,如果 SQL,查询是端点的属性,它使用消息有效负载作为传递给查询的参数。

CamelContext camelctx = new DefaultCamelContext();
camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("sql:select name from information_schema.users?dataSource=java:jboss/datasources/ExampleDS")
        .to("direct:end");
    }
});
注意

上方显示的 JNDI 数据源查找仅在配置 DefaultCamelContext 时正常工作。请参阅以下关于 CdiCamelContextSpringCamelContext 示例。

当与 camel-cdi 组件一同使用时,Jarkarta EE 注解可以向 Camel 提供数据源。本例使用 @Named 注释,以便 Camel 能够发现所需的数据源。

public class DatasourceProducer {
    @Resource(lookup = "java:jboss/datasources/ExampleDS")
    DataSource dataSource;

    @Produces
    @Named("wildFlyExampleDS")
    public DataSource getDataSource() {
        return dataSource;
    }
}

现在,数据源可以通过 camel-sql 端点配置上的 dataSource 参数来引用。

@ApplicationScoped
@ContextName("camel-sql-cdi-context")
@Startup
public class CdiRouteBuilder extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        from("sql:select name from information_schema.users?dataSource=wildFlyExampleDS")
        .to("direct:end");
    }
}

使用 camel-spring 时,路由配置将类似如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jee="http://www.springframework.org/schema/jee"
       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
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">

    <jee:jndi-lookup id="wildFlyExampleDS" jndi-name="java:jboss/datasources/ExampleDS"/>

    <camelContext id="sql-spring-context" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="sql:select name from information_schema.users?dataSource=#wildFlyExampleDS" />
            <to uri="direct:end" />
        </route>
    </camelContext>

</beans>

6.6.1. Spring JDBC XML 命名空间支持

支持以下 Spring JDBC XML 配置

jdbc:embedded-database

<jdbc:embedded-database id="datasource" type="H2">
  <jdbc:script location="db-schema.sql"/>
</jdbc:embedded-database>
注意

默认情况下只支持 H2 数据库,因为 JBoss EAP 具有此支持的原生支持。如果要使用其他嵌入式数据库供应商,则需要安装适当的数据库驱动程序。

jdbc:initialize-database

<jdbc:initialize-database data-source="datasource">
  <jdbc:script location="classpath:db-init.sql"/>
</jdbc:initialize-database>

6.7. camel-soap-rest-bridge

简单的 Camel 路由可以将 REST 调用桥接到旧 SOAP 服务。提供了 Quickstart 示例,演示使用 Camel 的 REST DSL( Camel 的 REST DSL)使用 camel-SOAp-rest-bridge 组件来公开后端 SOAP API 服务。

在此快速入门中,由 RH SSO 支持的 REST 端点和 SOAP 端点都涉及到安全性。前端 REST API 通过 OAuth 和 OpenID Connect 保护,客户端将使用 "Resource Owner Password Credentials" OAuth2 模式从 RH SSO 获取 JWT(JSON Web 令牌)访问令牌。客户端使用此令牌访问 REST 端点。

在网桥 Camel 路由中,客户端身份从 SecurityContext 传播,当 camel-cxf producer 与后端 WS-SECURITY 保护的 SOAP 服务对话时,它将首先使用此客户端身份获取由 CXF STS 服务发布的 SAML2 令牌(由 RH SSO 作为身份提供程序支持)。SAML2 令牌已签名并添加到 WS-SECURITY 标头中,后端 WS-SECURITY 保护的 SOAP 服务将验证此 SAML2 令牌。

SOAP 调用还包括 XSD 架构验证。如果令牌验证成功,后端 SOAP 服务会返回对发起请求的 REST 客户端的响应。

先决条件

  1. 已安装 JBoss EAP 7.3 或更高版本。
  2. 已安装 Apache Maven 3.3.x 或更高版本。
  3. 已安装并配置了 RH SSO 7.4 - 按照安装说明 https://access.redhat.com/documentation/zh-cn/red_hat_single_sign-on/7.4/html/getting_started_guide/installing-standalone_#installing-server-product
  4. 已安装 RH SSO EAP 适配器 - 按照安装说明 https://access.redhat.com/documentation/zh-cn/red_hat_single_sign-on/7.4/html/getting_started_guide/securing-sample-app_#installing-client-adapter

设置快速入门

  1. 以单机模式启动 JBOSS EAP。
  2. 导航到 EAP_HOME/quickstarts/camel/camel-SOAp-rest-bridge
  3. 输入 mvn clean install -Pdeploy 以构建和部署 Quickstart。
  4. 配置 RH SSO

    1. http://localhost:8180/auth 使用 admin 作为用户名/密码登录 RH SSO Admin Console
    2. Add realm
    3. Select file
    4. 选择 ./src/main/resources/keycloak-config/realm-export-new.json,该示例将导入预定义所需的 realm/client/user/role。
    5. Create

EAP 上的 Fuse 中的 Quickstart 示例

此快速入门示例包含有关运行快速启动和测试案例结果的附加信息,可在 EAP 安装中使用 EAP 安装( EAP_HOME/quickstarts/camel/camel-soap-rest-bridge 目录)。

取消部署

要取消部署示例,请导航到 EAP_HOME/quickstarts/camel/camel-soap-rest-bridge 目录,并运行 mvn clean -Pdeploy

6.8. 添加组件

为附加 Camel 组件添加支持非常简单

添加 module.xml 定义

module.xml 描述符可定义您的组件的类加载行为。它应该被放入 modules/system/layers/fuse/org/apache/camel/component 中组件的 jar。为直接编译时间依赖项,应设置模块依赖项。

下面是 camel-ftp 组件的示例

<module xmlns="urn:jboss:module:1.1" name="org.apache.camel.component.ftp">
  <resources>
    <resource-root path="camel-ftp-2.14.0.jar" />
  </resources>
  <dependencies>
    <module name="com.jcraft.jsch" />
    <module name="javax.xml.bind.api" />
    <module name="org.apache.camel.core" />
    <module name="org.apache.commons.net" />
  </dependencies>
</module>

请确保您没有已在 WildFly 中提供且可重复使用的模块。

添加对组件的引用

要使此模块默认对任意 JavaEE 部署可见,请添加对 modules/system/layers/fuse/org/apache/camel/component/main/module.xml的引用

<module xmlns="urn:jboss:module:1.3" name="org.apache.camel.component">
  <dependencies>
    ...
    <module name="org.apache.camel.component.ftp" export="true" services="export"/>
  </dependencies>
</module>

第 7 章 安全性

JBoss EAP 中的安全性是一个很大的主题。JBoss EAP 和 Camel 均有良好的记录,规范配置、端点和载荷的安全方法。

7.1. Hawtio 安全

可以通过下列步骤来保护 Hawtio 控制台。

1.在 standalone.xml 中添加系统属性

<system-properties>
    <property name="hawtio.authenticationEnabled" value="true" />
    <property name="hawtio.realm" value="hawtio-domain" />
</system-properties>

2.在 security 子系统中为 Hawtio 添加安全域

<security-domain name="hawtio-domain" cache-type="default">
    <authentication>
        <login-module code="RealmDirect" flag="required">
            <module-option name="realm" value="ManagementRealm"/>
        </login-module>
    </authentication>
</security-domain>

3.配置管理用户

$JBOSS_HOME/bin/add-user.sh -u someuser -p s3cret

浏览 http://localhost:8080/hawtio,并使用为管理用户配置的凭据进行身份验证。

7.2. JAX-RS 安全性

以下主题解释了如何保护 JAX-RS 端点。

7.3. JAX-WS Security

以下主题解释了如何保护 JAX-WS 端点。

7.4. JMS 安全性

以下主题解释了如何保护 JMS 端点。

另外,您可以使用 Camel 认为路由策略与 JBoss EAP 安全系统集成。

7.5. 路由策略

Camel 支持 RoutePolicies 的概念,可用于与 JBoss EAP 安全系统集成。目前有两种支持的安全集成场景。

7.5.1. Camel 称为 Jarkarta EE

当 camel 路由调用受保护的 Jarkarta EE 组件时,它会作为客户端提供与调用关联的适当凭证。

您可以使用 ClientAuthorizationPolicy 分离路由,如下所示:

CamelContext camelctx = new DefaultCamelContext();
camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("direct:start")
        .policy(new ClientAuthorizationPolicy())
        .to("ejb:java:module/AnnotatedSLSB?method=doSelected");
    }
});

这不会进行任何身份验证和授权,作为 camel 消息处理的一部分。相反,它会将 Camel Exchange 附带的凭据与调用 EJB3 层相关联。

调用消息消费者的客户端必须在 AUTHENTICATION 标头中提供适当的凭证,如下所示:

ProducerTemplate producer = camelctx.createProducerTemplate();
Subject subject = new Subject();
subject.getPrincipals().add(new DomainPrincipal(domain));
subject.getPrincipals().add(new EncodedUsernamePasswordPrincipal(username, password));
producer.requestBodyAndHeader("direct:start", "Kermit", Exchange.AUTHENTICATION, subject, String.class);

认证和授权将在 Jarkarta EE 层中进行。

7.5.2. 保护 Camel 路由

为了保护 Camel 路由,您可以将 DomainAuthorizationPolicy 与路由关联。此策略要求针对给定的安全域和"Role2"授权成功身份验证。

CamelContext camelctx = new DefaultCamelContext();
camelctx.addRoutes(new RouteBuilder() {
    @Override
    public void configure() throws Exception {
        from("direct:start")
        .policy(new DomainAuthorizationPolicy().roles("Role2"))
        .transform(body().prepend("Hello "));
    }
});
camelctx.start();

同样,调用消息消费者的客户端必须在 AUTHENTICATION 标头中提供适当的凭证,如下所示:

ProducerTemplate producer = camelctx.createProducerTemplate();
Subject subject = new Subject();
subject.getPrincipals().add(new DomainPrincipal(domain));
subject.getPrincipals().add(new EncodedUsernamePasswordPrincipal(username, password));
producer.requestBodyAndHeader("direct:start", "Kermit", Exchange.AUTHENTICATION, subject, String.class);

7.6. 部署 CXF JAX-WS 快速入门

本示例演示了在 EAP 上使用 camel-cxf 组件来生成和使用由 Elytron 安全域保护的 JAX-WS Web 服务。Elytron 是自 EAP 7.1 起提供的一个新安全框架。在此快速入门中,Camel 路由从直接端点获取消息有效负载,并将其传递给 CXF producer 端点。producer 使用有效负载将参数传递给 BASIC HTTP 身份验证保护的 CXF JAX-WS Web 服务。

先决条件

  • 确保已安装和配置 Maven。
  • 确保安装和配置了具有 Red Hat Fuse 的应用程序服务器。

流程

  1. 设置 JBOSS_HOME 环境变量,以指向应用服务器安装的根目录。

    • 对于 Linux

      export JBOSS_HOME=...
    • 对于 Windows:

      set JBOSS_HOME=...
  2. 使用 add-user 脚本创建新服务器应用用户和组。

    • 对于 Linux

      ${JBOSS_HOME}/bin/add-user.sh -a -u testUser -p testPassword1+ -g testRole
    • 对于 Windows:

      %JBOSS_HOME%\bin\add-user.bat -a -u testUser -p testPassword1+ -g testRole
  3. 以独立模式启动应用服务器。

    • 对于 Linux

      ${JBOSS_HOME}/bin/standalone.sh -c standalone-full.xml
    • 对于 Windows:

      %JBOSS_HOME%\bin\standalone.bat -c standalone-full.xml

      此项目的 webapp/WEB-INF 目录中的 jboss-web-xmlweb.xml 文件设置应用程序安全性域、安全角色和限制。

  4. 构建和部署项目。

    mvn install -Pdeploy

    此命令还调用 CLI 脚本 configure-basic-security.cli,用于创建安全域和一些其他管理对象。

  5. 浏览至 http://localhost:8080/example-camel-cxf-jaxws-secure/

    此时会显示标题为 Send A Greeting 的页面。此 UI 可让您与已启动的 测试 问候 Web 服务进行交互。服务 WSDL 位于 http://localhost:8080/webservices/greeting-security-basic?wsdl

    单个服务操作名为 greet,它取两个名为 messagename 的 String 参数。调用 Web 服务将返回这些值链接在一起的响应。

测试 Camel Secure CXF JAX-WS 快速入门

  1. 浏览至 http://localhost:8080/example-camel-cxf-jaxws-secure/
  2. Send A Greeting web 表单上,在文本字段中输入 消息和 名称,然后按" 发送 "按钮。

    您输入的信息显示为 UI 上的问候语。CamelCxfWsServlet 处理来自 Web UI 的 POST 请求。它从参数值中检索消息和名称,并构造对象数组。此对象数组是发送到 direct:start 端点的消息有效负载。ProducerTemplate 将消息有效负载发送到 Camel。direct:start 端点将对象数组传递到 cxf:bean web 服务制作者。CamelCxfWsServlet 使用 Web 服务响应来显示 Web UI 上的问候语。您可以在 src/main/webapp/WEB-INF/cxfws-security-camel-context.xml 文件中查看完整的 Camel 路由。

取消部署快速入门

  1. 运行以下命令以取消部署 quickstart。

    mvn clean -Pdeploy

法律通告

Copyright © 2023 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.