3.2. Spring Boot
Spring Boot 会自动为您配置 Camel。Camel 上下文自动探测到 Spring 上下文中提供的 Camel 路由,并将密钥 Camel 实用程序(如生成者模板、消费者模板和类型转换器)注册为 Bean。
Maven 用户需要将以下依赖项添加到其 pom.xml 中,以便使用此组件:
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot</artifactId>
</dependency>
camel-spring-boot jar 附带 spring.factories 文件,因此当您将该依赖项添加到类路径时,Spring Boot 将自动为您配置 Camel。
3.2.1. Camel Spring Boot Starter 复制链接链接已复制到粘贴板!
Apache Camel 提供了一个 Spring Boot Starter 模块,允许您使用 starters 开发 Spring Boot 应用程序。
example 存储库中也提供了 示例应用程序。
要使用启动程序,将以下内容添加到 spring boot pom.xml 文件中:
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
然后,您可以使用 Camel 路由添加类,例如:
package com.example;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
@Component
public class MyRoute extends RouteBuilder {
@Override
public void configure() throws Exception {
from("timer:foo").to("log:bar");
}
}
然后,这些路由将自动启动。
您可以在 application.properties 或 application.yml 文件中自定义 Camel 应用程序。
3.2.2. Spring Boot 自动配置 复制链接链接已复制到粘贴板!
当在 Spring Boot 中使用 spring-boot 时,请确保使用以下 Maven 依赖项来支持自动配置:
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
3.2.3. 自动配置的 Camel 上下文 复制链接链接已复制到粘贴板!
Camel 自动配置提供的最重要功能是 CamelContext 实例。Camel 自动配置为您创建一个 SpringCamelContext,并负责正确初始化和关闭该上下文。创建的 Camel 上下文也在 Spring 应用程序上下文中注册(在 camelContext bean 名称下),因此您可以像任何其他 Spring bean 一样访问它。
@Configuration
public class MyAppConfig {
@Autowired
CamelContext camelContext;
@Bean
MyService myService() {
return new DefaultMyService(camelContext);
}
}
3.2.4. 自动探测 Camel 路由 复制链接链接已复制到粘贴板!
Camel 自动配置从 Spring 上下文收集所有 RouteBuilder 实例,并自动将它们注入到提供的 CamelContext 中。这意味着,使用 Spring Boot starter 创建新的 Camel 路由非常简单,就像将 @Component 注解类添加到您的 classpath 中一样简单:
@Component
public class MyRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
from("jms:invoices").to("file:/invoices");
}
}
或者在您的 @Configuration 类中创建新的路由 RouteBuilder bean:
@Configuration
public class MyRouterConfiguration {
@Bean
RoutesBuilder myRouter() {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("jms:invoices").to("file:/invoices");
}
};
}
}
3.2.5. Camel 属性 复制链接链接已复制到粘贴板!
Spring Boot 自动配置会使用 Camel 属性支持自动连接到 Spring Boot 外部配置 (可能包含属性占位符、操作系统环境变量或系统属性)。它基本上表示 application.properties 文件中定义的任何属性:
route.from = jms:invoices
或者通过系统属性设置:
java -Droute.to=jms:processed.invoices -jar mySpringApp.jar
可用作 Camel 路由中的占位符:
@Component
public class MyRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
from("{{route.from}}").to("{{route.to}}");
}
}
3.2.6. 自定义 Camel 上下文配置 复制链接链接已复制到粘贴板!
如果要对 CamelContext bean 创建的 CamelContext bean 执行一些操作,请在 Spring 上下文中注册 CamelContextConfiguration 实例:
@Configuration
public class MyAppConfig {
@Bean
CamelContextConfiguration contextConfiguration() {
return new CamelContextConfiguration() {
@Override
void beforeApplicationStart(CamelContext context) {
// your custom configuration goes here
}
};
}
}
在启动 Spring 上下文 之前,才会调用ApplicationStart 的方法,因此传递给此回调的 CamelContext 实例会被完全自动配置。如果您在 Spring 上下文中添加多个 CamelContextConfiguration 实例,则每个实例都会被执行。
如需示例应用程序,请参阅 camel-spring-boot-examples 存储库中的 Metrics 示例。
3.2.7. 自动配置的消费者和制作者模板 复制链接链接已复制到粘贴板!
Camel 自动配置提供预配置的 ConsumerTemplate 和 ProducerTemplate 实例。您可以简单地将它们注入到 Spring 管理的 Bean 中:
@Component
public class InvoiceProcessor {
@Autowired
private ProducerTemplate producerTemplate;
@Autowired
private ConsumerTemplate consumerTemplate;
public void processNextInvoice() {
Invoice invoice = consumerTemplate.receiveBody("jms:invoices", Invoice.class);
...
producerTemplate.sendBody("netty-http:http://invoicing.com/received/" + invoice.id());
}
}
默认情况下,消费者模板和制作者模板将端点缓存大小设置为 1000。您可以通过修改以下 Spring 属性来更改这些值:
camel.springboot.consumer-template-cache-size = 100
camel.springboot.producer-template-cache-size = 200
3.2.8. 自动配置的类型Converter 复制链接链接已复制到粘贴板!
Camel 自动配置注册 Spring 上下文中名为 typeConverter 的 TypeConverter 实例。
@Component
public class InvoiceProcessor {
@Autowired
private TypeConverter typeConverter;
public long parseInvoiceValue(Invoice invoice) {
String invoiceValue = invoice.grossValue();
return typeConverter.convertTo(Long.class, invoiceValue);
}
}
3.2.8.1. Spring 类型转换 API 网桥 复制链接链接已复制到粘贴板!
Spring 附带强大的 类型转换 API。Spring API 与 Camel 类型转换器 API 类似。因为这两个 API 都类似,Camel Spring Boot 会自动注册一个网桥转换器(SpringTypeConverter),其委托给 Spring conversion API。这意味着,开箱即用的 Camel 将对待 Spring Converters,如 Camel。使用此方法,您可以使用通过 Camel TypeConverter API 访问的 Camel 和 Spring 转换器:
@Component
public class InvoiceProcessor {
@Autowired
private TypeConverter typeConverter;
public UUID parseInvoiceId(Invoice invoice) {
// Using Spring's StringToUUIDConverter
UUID id = invoice.typeConverter.convertTo(UUID.class, invoice.getId());
}
}
在 hood Camel Spring Boot 下,将转换委派给应用程序上下文中提供的 Spring ConversionService 实例。如果没有 ConversionService 实例,则 Camel Spring Boot 自动配置会为您创建一个。
如需示例应用程序,请参阅 camel-spring-boot-examples 存储库中的 Type 转换示例。
3.2.9. 使应用程序保持活跃 复制链接链接已复制到粘贴板!
启用了此功能的 Camel 应用程序在启动时会启动一个新线程,从而通过防止 JVM 终止来保持应用程序保持处于活动状态的唯一目的。这意味着,在使用 Spring Boot 启动 Camel 应用程序后,应用程序会等待 Ctrl+C 信号,且不会立即退出。
可以使用 camel.springboot.main-run-controller 作为 true 激活控制器线程。
camel.springboot.main-run-controller = true
使用 Web 模块(例如,导入 org.springframework.boot:spring-boot-web-starter 模块的应用程序)的应用程序通常不需要使用此功能,因为应用程序由其他非守护进程线程保留。
如需示例应用程序,请参阅 camel-spring-boot-examples 存储库中的 POJO 示例。
3.2.10. 添加 XML 路由 复制链接链接已复制到粘贴板!
默认情况下,您可以将 Camel XML 路由放在目录 camel 下的 classpath 中,camel-spring-boot 将 auto-detect 和 include。您可以使用配置选项配置目录名称或关闭它:
# turn off
camel.springboot.routes-include-pattern = false
# scan only in the com/foo/routes classpath
camel.springboot.routes-include-pattern = classpath:com/foo/routes/*.xml
XML 文件应为 Camel XML 路由(而不是 < CamelContext>),例如:
<routes xmlns="http://camel.apache.org/schema/spring">
<route id="test">
<from uri="timer://trigger"/>
<transform>
<simple>ref:myBean</simple>
</transform>
<to uri="log:out"/>
</route>
</routes>
有关示例应用程序,请参阅 camel-spring-boot-examples 存储库中的 XML 示例。
3.2.11. 测试 JUnit 5 方法 复制链接链接已复制到粘贴板!
对于测试,Maven 用户需要将以下依赖项添加到其 pom.xml 中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring-junit5</artifactId>
<scope>test</scope>
</dependency>
要测试 Camel Spring Boot 应用程序,请使用 @CamelSpringBootTest 注解测试类。这会为应用程序提供 Camel 的 Spring Test 支持,以便您可以使用 Spring Boot 测试惯例编写测试。
要获取 CamelContext 或 ProducerTemplate,您可以使用 @Autowired 以普通的 Spring 方法将它们注入类。
您还可以使用 camel-test-spring-junit5 来配置测试。本例使用 @MockEndpoints 注释自动模拟端点:
@CamelSpringBootTest
@SpringBootApplication
@MockEndpoints("direct:end")
public class MyApplicationTest {
@Autowired
private ProducerTemplate template;
@EndpointInject("mock:direct:end")
private MockEndpoint mock;
@Test
public void testReceive() throws Exception {
mock.expectedBodiesReceived("Hello");
template.sendBody("direct:start", "Hello");
mock.assertIsSatisfied();
}
}
有关示例应用程序,请参阅 camel-spring-boot-examples 存储库中的 Infinispan 示例。
@CamelSpringBootTest 扩展 @SpringBootTest 功能,包括功能,外加: - 提供路由测试实用程序 - 包括 CamelContext、路由公告和模拟端点 - 启用 Camel 测试注解 - Works 带有 @MockEndpoints、@UseAdviceWith 等。
@UseAdviceWith 的示例是在运行时应用路由修改时:
package com.redhat;
....
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
....
@CamelSpringBootTest
@SpringBootApplication
public class MySpringBootApplicationTest {
@Autowired
private CamelContext camelContext;
@Autowired
private ProducerTemplate producerTemplate;
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplicationTest.class, args);
}
// Spring context fixtures
@Configuration
static class TestConfig {
@Bean
RoutesBuilder route() {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("timer:hello1?period={{timer.period}}").routeId("hello1")
.transform().method("myBean", "saySomething")
.filter(simple("${body} contains 'foo'"))
.to("log:foo")
.end()
.to("stream:out");
}
};
}
}
@Test
public void test() throws Exception {
// Apply advice before getting the mock endpoint
AdviceWith.adviceWith(camelContext, "hello1",
// intercepting an exchange on route
r -> {
// replacing consumer with direct component
r.replaceFromWith("direct:start");
// mocking producer
r.mockEndpoints("stream*");
}
);
// Start the context after applying advice
camelContext.start();
// Get mock endpoint after advice is applied
MockEndpoint mock = camelContext.getEndpoint("mock:stream:out", MockEndpoint.class);
// setting expectations
mock.expectedMessageCount(1);
mock.expectedBodiesReceived("Hello World");
// invoking consumer
producerTemplate.sendBody("direct:start", null);
// asserting mock is satisfied
mock.assertIsSatisfied();
}
}
在某些情况下,我们需要声明(使用 @CamelSpringBootTest 和 @SpringBootTest 的组合),当应用程序Context 严格要求时,只需添加 @SpringBootTest (classes = DocTest.TestApplication.class) 来指定要使用的配置类:
package com.redhat;
....
import org.apache.camel.EndpointInject;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.apache.camel.test.spring.junit5.MockEndpoints;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
....
@CamelSpringBootTest
@SpringBootTest(classes = MySpringBootApplicationTest.TestConfig.class)
@SpringBootApplication
@MockEndpoints("direct:end")
public class MySpringBootApplicationTest {
@Autowired
private ProducerTemplate template;
@EndpointInject("mock:direct:end")
private MockEndpoint mock;
@Configuration
static class TestConfig {
@Bean
RoutesBuilder route() {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:start").routeId("hello2")
.setBody(simple("Hello World"))
.log("Received: ${body}")
.to("direct:end");
from("direct:end")
.log("${body}");
}
};
}
}
@Test
public void testReceive() throws Exception {
mock.expectedMessageCount(1);
mock.expectedBodiesReceived("Hello World");
template.sendBody("direct:start", null);
mock.assertIsSatisfied();
}
}
另一种方法是测试典型的 Spring XML 上下文设置。在这种情况下,我们需要使用 @ContextConfiguration 指定 XML 文件,通过依赖项注入检索 Main Camel 运行时上下文:
@Autowired
protected CamelContext camelContext;
然后,在每个测试方法后重新载入 Spring ApplicationContext:
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
备选模式: BEFORE_CLASS,AFTER_CLASS,BEFORE_EACH_TEST_METHOD
下面描述了一个完整的示例:
package com.redhat.plain;
....
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
....
@CamelSpringBootTest
@ContextConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class MySpringBootApplicationPlainTest {
@Autowired
protected CamelContext camelContext;
@EndpointInject("mock:a")
protected MockEndpoint mockA;
@Produce("direct:start")
protected ProducerTemplate start;
@Test
public void testPositive() throws Exception {
assertEquals(ServiceStatus.Started, camelContext.getStatus());
start.sendBody("Hello");
MockEndpoint.assertIsSatisfied(camelContext);
mockA.expectedBodiesReceived("Hello");
}
}
其中 Spring XML 上下文需要放在声明的类软件包 com.redhat.plain 中的资源下,使用命名模式 className-context.xml
项目结构
src/
├── main/ [yaml context structure]
│ ├── java/
│ │ └─── com/redhat/
│ │ ├── Application.java
│ │ └── route/
│ │ └── MyRoute.java
│ │
│ └── resources/
│ └── application.yml
└── test/ [xml context structure]
├── java/
│ └─ com/redhat/plain
│ ├── MySpringBootApplicationPlainTest.java
│ └── route/
│ └── MyRoute.java
└── resources/
└── com/redhat/plain
└── MySpringBootApplicationPlainTest-context.xml
上例的 XML 声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
">
<!-- Camel Context configuration -->
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<route xmlns="http://camel.apache.org/schema/spring" id="helloX">
<from id="from1" uri="direct:start"/>
<filter id="filter1">
<simple>${body} contains 'foo'</simple>
<to id="to1" uri="log:foo"/>
</filter>
<to id="to2" uri="stream:out"/>
</route>
</camelContext>
</beans>