Java
Since Camel 4.3 自从骆驼 4.3 版本以来
The Java language (uses jOOR library to compile Java code) allows using Java code in your Camel expression, with some limitations.
Java 语言(使用 jOOR 库编译 Java 代码)允许在 Camel 表达式中使用 Java 代码,但有一些限制。
The jOOR library integrates with the Java compiler and performs runtime compilation of Java code.
jOOR 库与 Java 编译器集成,并对 Java 代码进行运行时编译。
Java Options JAVA 选项
The Java language supports 4 options, which are listed below.
Java 语言支持以下 4 个选项。
Name 姓名 | Default 默认 | Java Type Java 类型 | Description 描述 |
---|---|---|---|
|
| Whether the expression should be pre compiled once during initialization phase. If this is turned off, then the expression is reloaded and compiled on each evaluation. | |
|
| Whether single quotes can be used as replacement for double quotes. This is convenient when you need to work with strings inside strings. | |
| Sets the class of the result type (type from output). | ||
|
| Whether to trim the value to remove leading and trailing whitespaces and line breaks. |
Variables 变量
The Java language allows the following variables to be used in the script:
Java 语言允许在脚本中使用以下变量:
Variable 变量 | Java Type Java 类型 | Description 描述 |
---|---|---|
context 背景 |
| The CamelContext CamelContext |
exchange 交换 |
| The Camel Exchange 骆驼交易所 |
message 消息 |
| The Camel message 骆驼消息 |
body 身体 |
| The message body 消息正文 |
Functions 功能
The Java language allows the following functions to be used in the script:
Java 语言允许在脚本中使用以下功能:
Function 功能 | Description 描述 |
---|---|
bodyAs(type) | To convert the body to the given type. |
headerAs(name, type) headerAs(名称,类型) | To convert the header with the name to the given type. |
headerAs(name, defaultValue, type) | To convert the header with the name to the given type. If no header exists, then use the given default value. |
exchangePropertyAs(name, type) | To convert the exchange property with the name to the given type. |
exchangePropertyAs(name, defaultValue, type) | To convert the exchange property with the name to the given type. If no exchange property exists, then use the given default value. |
optionalBodyAs(type) 可选的 BodyAs(type) | To convert the body to the given type, returned wrapped in |
optionalHeaderAs(name, type) | To convert the header with the name to the given type, returned wrapped in |
optionalExchangePropertyAs(name, type) | To convert the exchange property with the name to the given type, returned wrapped in |
These functions are convenient for getting the message body, header or exchange properties as a specific Java type.
这些函数方便地将消息体、头部或交换属性作为特定的 Java 类型获取。
Here we want to get the message body as a com.foo.MyUser
type we can do as follows:
在这里,我们想要将消息正文作为 com.foo.MyUser
类型获取,可以按照以下方式进行操作:
var user = bodyAs(com.foo.MyUser.class);
You can omit .class to make the function a little smaller:
您可以省略 .class 以使函数变得更小:
var user = bodyAs(com.foo.MyUser);
The type must be a fully qualified class type, but that can be inconvenient to type all the time. In such a situation, you can configure an import in the camel-joor.properties
file as shown below:
类型必须是一个完全限定的类类型,但是每次都输入完整的类名可能会不方便。在这种情况下,您可以在 camel-joor.properties
文件中配置一个导入,如下所示:
import com.foo.MyUser;
And then the function can be shortened:
然后这个函数可以被简化:
var user = bodyAs(MyUser);
Dependency Injection 依赖注入
The Camel Java language allows dependency injection by referring to beans by their id from the Camel registry. For optimization purposes, then the beans are injected once in the constructor and the scopes are singleton. This requires the injected beans to be thread safe as they will be reused for all processing.
Camel Java 语言允许通过从 Camel 注册表中引用 bean 的 id 来进行依赖注入。为了优化目的,这些 bean 在构造函数中只被注入一次,并且作用域是单例的。这要求被注入的 bean 在所有处理过程中都是线程安全的,因为它们将被重复使用。
In the Java code you declare the injected beans using the syntax #bean:beanId
.
在 Java 代码中,您可以使用 #bean:beanId
语法声明注入的 bean。
For example, suppose we have the following bean
例如,假设我们有以下的 bean
public class MyEchoBean {
public String echo(String str) {
return str + str;
}
public String greet() {
return "Hello ";
}
}
And this bean is registered with the name myEcho
in the Camel registry.
这个 bean 在 Camel 注册表中以名称 myEcho
注册。
The Java code can then inject this bean directly in the script where the bean is in use:
Java 代码可以直接在使用该 bean 的脚本中注入该 bean
from("direct:start")
.transform().java("'Hello ' + #bean:myEcho.echo(bodyAs(String))")
.to("mock:result");
Now this code may seem a bit magic, but what happens is that the myEcho
bean is injected via a constructor, and then called directly in the script, so it is as fast as possible.
现在这段代码可能看起来有点神奇,但实际上的情况是 myEcho
bean 通过构造函数注入,然后在脚本中直接调用,所以速度尽可能快。
Under the hood, Camel Java generates the following source code compiled once:
在底层,Camel Java 生成以下源代码,只编译一次:
public class JoorScript1 implements org.apache.camel.language.joor.JoorMethod {
private MyEchoBean myEcho;
public JoorScript1(CamelContext context) throws Exception {
myEcho = context.getRegistry().lookupByNameAndType("myEcho", MyEchoBean.class);
}
@Override
public Object evaluate(CamelContext context, Exchange exchange, Message message, Object body, Optional optionalBody) throws Exception {
return "Hello " + myEcho.echo(bodyAs(exchange, String.class));
}
}
You can also store a reference to the bean in a variable which would more resemble how you would code in Java
您还可以将对 bean 的引用存储在一个变量中,这样更接近您在 Java 中编写代码的方式
from("direct:start")
.transform().java("var bean = #bean:myEcho; return 'Hello ' + bean.echo(bodyAs(String))")
.to("mock:result");
Notice how we declare the bean as if it is a local variable via var bean = #bean:myEcho
. When doing this we must use a different name as myEcho
is the variable used by the dependency injection. Therefore, we use bean as name in the script.
注意我们如何通过 var bean = #bean:myEcho
将 bean 声明为局部变量。在这样做时,我们必须使用不同的名称,因为 myEcho
是依赖注入使用的变量。因此,在脚本中我们使用 bean 作为名称。
Auto imports 汽车进口
The Java language will automatically import from:
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
import org.apache.camel.*;
import org.apache.camel.util.*;
Configuration file 配置文件
You can configure the jOOR language in the camel-joor.properties
file which by default is loaded from the root classpath. You can specify a different location with the configResource
option on the Java language.
您可以在默认情况下从根类路径加载的 camel-joor.properties
文件中配置 jOOR 语言。您可以使用 Java 语言的 configResource
选项指定不同的位置。
For example, you can add additional imports in the camel-joor.properties
file by adding:
例如,您可以通过添加以下内容在 camel-joor.properties
文件中添加额外的导入:
import com.foo.MyUser;
import com.bar.*;
import static com.foo.MyHelper.*;
You can also add aliases (key=value
) where an alias will be used as a shorthand replacement in the code.
您还可以添加别名( key=value
),其中别名将在代码中用作简写替代。
echo()=bodyAs(String) + bodyAs(String)
Which allows using echo()
in the jOOR language script such as:
允许在 jOOR 语言脚本中使用 echo()
from("direct:hello")
.transform(java("'Hello ' + echo()"))
.log("You said ${body}");
The echo()
alias will be replaced with its value resulting in a script as:
echo()
别名将被替换为其值,生成的脚本如下:
.transform(java("'Hello ' + bodyAs(String) + bodyAs(String)"))
You can configure a custom configuration location for the camel-joor.properties
file or reference to a bean in the registry:
您可以为 camel-joor.properties
文件配置自定义配置位置,或者引用注册表中的 bean
JavaLanguage joor = (JavaLanguage) context.resolveLanguage("java");
java.setConfigResource("ref:MyJoorConfig");
And then register a bean in the registry with id MyJoorConfig
that is a String value with the content.
然后在注册表中注册一个 id 为 MyJoorConfig
的 bean,它是一个包含内容的字符串值。
String config = "....";
camelContext.getRegistry().put("MyJoorConfig", config);
Example 例子
For example, to transform the message using jOOR language to the upper case
例如,使用 jOOR 语言将消息转换为大写
from("seda:orders")
.transform().java("message.getBody(String.class).toUpperCase()")
.to("seda:upper");
And in XML DSL:
在 XML DSL 中:
<route>
<from uri="seda:orders"/>
<transform>
<java>message.getBody(String.class).toUpperCase()</joor>
</transform>
<to uri="seda:upper"/>
</route>
Multi statements 多语句
It is possible to include multiple statements. The code below shows an example where the user
header is retrieved in a first statement. And then, in a second statement we return a value whether the user is null
or not.
可以包含多个语句。下面的代码示例中,第一个语句中检索到 user
头部。然后,在第二个语句中,我们返回一个值,判断用户是否 null
。
from("seda:orders")
.transform().java("var user = message.getHeader(\"user\"); return user != null ? \"User: \" + user : \"No user exists\";")
.to("seda:user");
Notice how we have to quote strings in strings, and that is annoying, so instead we can use single quotes:
注意我们在字符串中需要引用字符串,这很烦人,所以我们可以使用单引号代替
from("seda:orders")
.transform().java("var user = message.getHeader('user'); return user != null ? 'User: ' + user : 'No user exists';")
.to("seda:user");
Hot re-load 热重新加载
You can turn off pre-compilation for the Java language and then Camel will recompile the script for each message. You can externalize the code into a resource file, which will be reloaded on each message as shown:
您可以关闭 Java 语言的预编译,然后 Camel 将为每个消息重新编译脚本。您可以将代码外部化到资源文件中,每个消息都会重新加载,如下所示:
JavaLanguage java = (JavaLanguage) context.resolveLanguage("java");
java.setPreCompile(false);
from("jms:incoming")
.transform().java("resource:file:src/main/resources/orders.java")
.to("jms:orders");
Here the Java code is externalized into the file src/main/resources/orders.java
which allows you to edit this source file while running the Camel application and try the changes with hot-reloading.
这里的 Java 代码被外部化到文件 src/main/resources/orders.java
中,这样你可以在运行 Camel 应用程序时编辑这个源文件,并尝试使用热加载进行更改。
In XML DSL it’s easier because you can turn off pre-compilation in the <java>
XML element:
在 XML DSL 中更容易,因为你可以在 <java>
XML 元素中关闭预编译
<route>
<from uri="jms:incoming"/>
<transform>
<java preCompile="false">resource:file:src/main/resources/orders.java</java>
</transform>
<to uri="jms:orders"/>
</route>
Lambda-based AggregationStrategy
基于 Lambda 的聚合策略
The Java language has special support for defining an org.apache.camel.AggregationStrategy
as a lambda expression. This is useful when using EIP patterns that use aggregation such as the Aggregator, Splitter, Recipient List, Enrich, and others.
Java 语言对于将 org.apache.camel.AggregationStrategy
定义为 lambda 表达式有特殊支持。在使用使用聚合等 EIP 模式(如聚合器、分割器、收件人列表、增强等)时,这非常有用。
To use this, then the Java language script must be in the following syntax:
要使用这个,那么 Java 语言脚本必须采用以下语法:
(e1, e2) -> { }
Where e1
and e2
are the old Exchange and new Exchange from the aggregate
method in the AggregationStrategy
. The returned value is used as the aggregated message body, or use null
to skip this.
其中 e1
和 e2
是 AggregationStrategy
方法中的旧交换和新交换。返回的值用作聚合消息的主体,或者使用 null
跳过此步骤。
The lambda syntax is representing a Java util BiFunction<Exchange, Exchange, Object>
type.
lambda 语法表示一个 Java util 类型。
For example, to aggregate message bodies together, we can do this as shown:
例如,要将消息正文聚合在一起,我们可以按如下所示进行操作:
(e1, e2) -> {
String b1 = e1.getMessage().getBody(String.class);
String b2 = e2.getMessage().getBody(String.class);
return b1 + ',' + b2;
}
Limitations 限制
The Java Camel language is only supported as a block of Java code that gets compiled into a Java class with a single method. The code that you can write is therefore limited to a number of Java statements.
Java 骆驼语言仅支持作为一块 Java 代码块,编译成一个具有单个方法的 Java 类。因此,您可以编写的代码受到一些 Java 语句的限制。
The supported runtime is intended for Java standalone, Spring Boot, Camel Quarkus and other microservices runtimes. It is not supported in OSGi, Camel Karaf or any kind of Java Application Server runtime.
支持的运行时适用于 Java 独立运行、Spring Boot、Camel Quarkus 和其他微服务运行时。它不支持 OSGi、Camel Karaf 或任何类型的 Java 应用服务器运行时。
Java does not support runtime compilation with Spring Boot using fat jar packaging (https://github.com/jOOQ/jOOR/issues/69), it works with exploded classpath.
Java 在使用 Spring Boot 进行 fat jar 打包时不支持运行时编译(https://github.com/jOOQ/jOOR/issues/69),但在使用爆炸式类路径时可以正常工作。
Dependencies 依赖
To use scripting languages in your camel routes, you need to add a dependency on camel-joor.
If you use Maven you could add the following to your pom.xml
, substituting the version number for the latest and greatest release.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-joor</artifactId>
<version>x.x.x</version>
</dependency>
Spring Boot Auto-Configuration
Spring Boot 自动配置
When using java with Spring Boot make sure to use the following Maven dependency to have support for auto configuration:
使用 Spring Boot 时,请确保使用以下 Maven 依赖项以获得自动配置支持:
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-joor-starter</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
The component supports 8 options, which are listed below.
该组件支持 8 个选项,如下所示。