Spring Integration (集成)消息传递终结点(三)_Java

日志记录通道适配器

Theis 通常与窃听器结合使用,如Wire Tap 中所讨论的。 但是,它也可以用作任何流的最终使用者。 例如,假设一个流以 a结尾,返回一个结果,但您希望放弃该结果。 为此,您可以将结果发送到。 或者,您可以将其路由到水平。 这样,您可以在级别记录时看到丢弃的消息,但在(例如)级别记录时看不到它。 使用 a,在级别记录时只会看到丢弃的消息。 下面的清单显示了元素的所有可能属性:​​<logging-channel-adapter>​​​​<service-activator>​​​​NullChannel​​​​INFO​​​​<logging-channel-adapter>​​​​INFO​​​​WARN​​​​NullChannel​​​​DEBUG​​​​logging-channel-adapter​

<int:logging-channel-adapter
channel=""
level="INFO"
expression=""
log-full-message="false"
logger-name="" />

将日志记录适配器连接到上游组件的通道。

将记录发送到此适配器的消息的日志记录级别。 违约:。​​INFO​

一个 SpEL 表达式,准确表示记录消息的哪些部分。 默认值:— 仅记录有效负载。 指定了 IFIS,则无法指定此属性。​​payload​​​​log-full-message​

何时,记录整个消息(包括标头)。 默认值:— 仅记录有效负载。 不能指定此属性 ifis。​​true​​​​false​​​​expression​

指定记录器(称为 asin)。 用于标识此适配器创建的日志消息。 这样就可以为单个适配器设置日志名称(在日志记录子系统中)。 默认情况下,所有适配器都以以下名称记录:。​​name​​​​category​​​​log4j​​​​org.springframework.integration.handler.LoggingHandler​

使用 Java 配置

以下 Spring 引导应用程序显示了使用 Java 配置进行配置的示例:​​LoggingHandler​

@SpringBootApplication
public class LoggingJavaApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(LoggingJavaApplication.class)
.web(false)
.run(args);
MyGateway gateway = context.getBean(MyGateway.class);
gateway.sendToLogger("foo");
}

@Bean
@ServiceActivator(inputChannel = "logChannel")
public LoggingHandler logging() {
LoggingHandler adapter = new LoggingHandler(LoggingHandler.Level.DEBUG);
adapter.setLoggerName("TEST_LOGGER");
adapter.setLogExpressionString("headers.id + ': ' + payload");
return adapter;
}

@MessagingGateway(defaultRequestChannel = "logChannel")
public interface MyGateway {

void sendToLogger(String data);

}

}

使用 Java DSL 进行配置

以下 Spring 引导应用程序显示了使用 Java DSL 配置日志记录通道适配器的示例:

@SpringBootApplication
public class LoggingJavaApplication {

public static void main(String[] args) {
ConfigurableApplicationContext context =
new SpringApplicationBuilder(LoggingJavaApplication.class)
.web(false)
.run(args);
MyGateway gateway = context.getBean(MyGateway.class);
gateway.sendToLogger("foo");
}

@Bean
public IntegrationFlow loggingFlow() {
return IntegrationFlow.from(MyGateway.class)
.log(LoggingHandler.Level.DEBUG, "TEST_LOGGER",
m -> m.getHeaders().getId() + ": " + m.getPayload());
}

@MessagingGateway
public interface MyGateway {

void sendToLogger(String data);

}

}

​java.util.function​​接口支持

从版本 5.1 开始,Spring 集成为软件包中的接口提供了直接支持。 所有消息传递端点(服务激活器、转换器、筛选器等)现在可以引用(或)bean。 消息传递注释可以直接应用于这些 bean,类似于常规定义。 例如,如果您有这个豆定义:​​java.util.function​​​​Function​​​​Consumer​​​​MessageHandler​​​​Function​

@Configuration
public class FunctionConfiguration {

@Bean
public Function<String, String> functionAsService() {
return String::toUpperCase;
}

}

您可以将其用作 XML 配置文件中的简单引用:

<service-activator input-channel="processorViaFunctionChannel" ref="functionAsService"/>

当我们使用消息传递注释配置流时,代码很简单:

@Bean
@Transformer(inputChannel = "functionServiceChannel")
public Function<String, String> functionAsService() {
return String::toUpperCase;
}

当函数返回一个数组时,(本质上是 any)或 Reactor,可以在这样的 bean 上使用,对结果内容执行迭代。​​Collection​​​​Iterable​​​​Stream​​​​Flux​​​​@Splitter​

该接口可用于 anor,与注释一起执行流的最后一步:​​java.util.function.Consumer​​​​<int:outbound-channel-adapter>​​​​@ServiceActivator​

@Bean
@ServiceActivator(inputChannel = "messageConsumerServiceChannel")
public Consumer<Message<?>> messageConsumerAsService() {
// Has to be an anonymous class for proper type inference
return new Consumer<Message<?>>() {

@Override
public void accept(Message<?> e) {
collector().add(e);
}

};
}

另外,请注意上面代码片段中的注释:如果您想处理您/您/中的整个消息,则不能使用 lambda 定义。 由于 Java 类型擦除,我们无法确定方法调用的目标类型。​​Function​​​​Consumer​​​​apply()/accept()​

该接口可以简单地与注释一起使用,也可以作为:​​java.util.function.Supplier​​​​@InboundChannelAdapter​​​​ref​​​​<int:inbound-channel-adapter>​

@Bean
@InboundChannelAdapter(value = "inputChannel", poller = @Poller(fixedDelay = "1000"))
public Supplier<String> pojoSupplier() {
return () -> "foo";
}

使用 Java DSL,我们只需要在端点定义中使用对函数 Bean 的引用。 同时,接口的实现可以用作常规定义:​​Supplier​​​​MessageSource​

@Bean
public Function<String, String> toUpperCaseFunction() {
return String::toUpperCase;
}

@Bean
public Supplier<String> stringSupplier() {
return () -> "foo";
}

@Bean
public IntegrationFlow supplierFlow() {
return IntegrationFlow.from(stringSupplier())
.transform(toUpperCaseFunction())
.channel("suppliedChannel")
.get();
}

当与 Spring Cloud 函数框架一起使用时,此函数支持非常有用,在Spring Cloud函数框架中,我们有一个函数目录,可以从集成流定义中引用其成员函数。

科特林支持

该框架也得到了改进,以支持 Kotlin lambda 的函数,所以现在你可以使用 Kotlin 语言和 Spring Integration 流程定义的组合:

@Bean
@Transformer(inputChannel = "functionServiceChannel")
fun kotlinFunction(): (String) -> String {
return { it.toUpperCase() }
}

@Bean
@ServiceActivator(inputChannel = "messageConsumerServiceChannel")
fun kotlinConsumer(): (Message<Any>) -> Unit {
return { print(it) }
}

@Bean
@InboundChannelAdapter(value = "counterChannel",
poller = Poller(fixedRate = "10", maxMessagesPerPoll = "1"))
fun kotlinSupplier(): () -> String {
return { "baz" }
}

Kotlin 协程

从 6.0 版开始,Spring Integration 提供了对Kotlin 协程的支持。 Nowfunctions 和 &return 类型可用于服务方法:​​suspend​​​​kotlinx.coroutines.Deferred​​​​kotlinx.coroutines.flow.Flow​

@ServiceActivator(inputChannel = "suspendServiceChannel", outputChannel = "resultChannel")
suspend fun suspendServiceFunction(payload: String) = payload.uppercase()

@ServiceActivator(inputChannel = "flowServiceChannel", outputChannel = "resultChannel", async = "true")
fun flowServiceFunction(payload: String) =
flow {
for (i in 1..3) {
emit("$payload #$i")
}
}

该框架将它们视为反应式流交互,并用于转换为相关和反应器类型。 这样的函数回复然后在回复通道中处理,如果它是一个,或者作为相应回调的结果。​​ReactiveAdapterRegistry​​​​Mono​​​​Flux​​​​ReactiveStreamsSubscribableChannel​​​​CompletableFuture​

带有结果的函数不是默认的,so实例是作为回复消息有效负载生成的。 目标应用程序负责将此对象作为协程处理或分别转换为协程。​​Flow​​​​async​​​​@ServiceActivator​​​​Flow​​​​Flux​

接口方法在 Kotlin 中声明时也可以用修饰符标记。 该框架利用内部使用下游流执行请求-回复。 这样的结果由 API 在内部处理,以满足网关调用函数的参数:​​@MessagingGateway​​​​suspend​​​​Mono​​​​Mono​​​​MonoKt.awaitSingleOrNull()​​​​kotlin.coroutines.Continuation​​​​suspend​

@MessagingGateway(defaultRequestChannel = "suspendRequestChannel")
interface SuspendFunGateway {

suspend fun suspendGateway(payload: String): String

}

此方法必须根据 Kotlin 语言要求作为协程调用:

@Autowired
private lateinit var suspendFunGateway: SuspendFunGateway

fun someServiceMethod() {
runBlocking {
val reply = suspendFunGateway.suspendGateway("test suspend gateway")
}
}