# MongoDB 支持
# MongoDB 支持
2.1 版引入了对MongoDB (opens new window)的支持:一个“高性能、开源、面向文档的数据库”。
你需要在项目中包含此依赖项:
Maven
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mongodb</artifactId>
<version>5.5.9</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-mongodb:5.5.9"
要下载、安装和运行 MongoDB,请参见MongoDB 文档 (opens new window)。
# 连接到 MongoDB
# 阻塞还是反应?
从版本 5.3 开始, Spring 集成提供了对反应式 MongoDB 驱动程序的支持,以便在访问 MongoDB 时启用非阻塞 I/O。要启用反应性支持,请将 MongoDB 反应性流驱动程序添加到你的依赖项中:
Maven
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
</dependency>
Gradle
compile "org.mongodb:mongodb-driver-reactivestreams"
对于常规的同步客户机,你需要将其各自的驱动程序添加到依赖项中:
Maven
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
</dependency>
Gradle
compile "org.mongodb:mongodb-driver-sync"
它们都是optional
框架中更好的终端用户选择支持。
要开始与 MongoDB 交互,你首先需要连接到它。 Spring 集成建立在另一个 Spring 项目Spring Data MongoDB (opens new window)提供的支持之上。它提供了名为MongoDatabaseFactory
和ReactiveMongoDatabaseFactory
的工厂类,这简化了与 MongoDB 客户机 API 的集成。
Spring 默认情况下提供的数据提供了阻塞的 MongoDB 驱动程序,但是你可以通过包括上述依赖项来 OPT 用于反应性使用。 |
---|
# 使用MongoDatabaseFactory
要连接到 MongoDB,你可以使用MongoDatabaseFactory
接口的实现。
下面的示例展示了如何使用SimpleMongoClientDatabaseFactory
:
爪哇
MongoDatabaseFactory mongoDbFactory =
new SimpleMongoClientDatabaseFactory(com.mongodb.client.MongoClients.create(), "test");
XML
<bean id="mongoDbFactory" class="o.s.data.mongodb.core.SimpleMongoClientDatabaseFactory">
<constructor-arg>
<bean class="com.mongodb.client.MongoClients" factory-method="create"/>
</constructor-arg>
<constructor-arg value="test"/>
</bean>
SimpleMongoClientDatabaseFactory
接受两个参数:一个MongoClient
实例和一个指定数据库名称的String
实例。如果需要配置host
、port
等属性,则可以使用底层MongoClients
类提供的一个构造函数来传递这些属性。有关如何配置 MongoDB 的更多信息,请参见Spring-Data-MongoDB (opens new window)引用。
# 使用ReactiveMongoDatabaseFactory
要使用 Reactive 驱动程序连接到 MongoDB,你可以使用ReactiveMongoDatabaseFactory
接口的实现。
下面的示例展示了如何使用SimpleReactiveMongoDatabaseFactory
:
爪哇
ReactiveMongoDatabaseFactory mongoDbFactory =
new SimpleReactiveMongoDatabaseFactory(com.mongodb.reactivestreams.client.MongoClients.create(), "test");
XML
<bean id="mongoDbFactory" class="o.s.data.mongodb.core.SimpleReactiveMongoDatabaseFactory">
<constructor-arg>
<bean class="com.mongodb.reactivestreams.client.MongoClients" factory-method="create"/>
</constructor-arg>
<constructor-arg value="test"/>
</bean>
# MongoDB 消息存储
正如Enterprise 整合模式一书中所描述的,消息存储 (opens new window)允许你持久化消息。在处理具有缓冲消息能力的组件(QueueChannel
,aggregator
,resequencer
,以及其他)时,如果可靠性是一个问题,那么这样做是有用的。在 Spring 集成中,MessageStore
策略还为索赔检查 (opens new window)模式提供了基础,这也在 EIP 中进行了描述。
Spring Integration 的 MongoDB 模块提供了MongoDbMessageStore
,这是MessageStore
策略(主要由索赔检查模式使用)和MessageGroupStore
策略(主要由聚合器和重排序模式使用)的实现。
下面的示例将MongoDbMessageStore
配置为使用QueueChannel
和aggregator
:
<bean id="mongoDbMessageStore" class="o.s.i.mongodb.store.MongoDbMessageStore">
<constructor-arg ref="mongoDbFactory"/>
</bean>
<int:channel id="somePersistentQueueChannel">
<int:queue message-store="mongoDbMessageStore"/>
<int:channel>
<int:aggregator input-channel="inputChannel" output-channel="outputChannel"
message-store="mongoDbMessageStore"/>
前面的示例是一个简单的 Bean 配置,它需要一个MongoDbFactory
作为构造函数参数。
MongoDbMessageStore
通过使用 Spring 数据 mongo 映射机制,将Message
扩展为具有所有嵌套属性的 mongo 文档。当你需要访问payload
或headers
以进行审计或分析(例如,针对存储的消息)时,它是有用的。
MongoDbMessageStore 使用自定义的MappingMongoConverter 实现将Message 实例存储为 MongoDB 文档,并且对Message 的属性(payload 和header 值)有一些限制。 |
---|
从版本 5.1.6 开始,MongoDbMessageStore
可以配置自定义转换器,这些转换器被传播到内部MappingMongoConverter
实现中。有关更多信息,请参见MongoDbMessageStore.setCustomConverters(Object… customConverters)
爪哇docs。
Spring Integration3.0 引入了ConfigurableMongoDbMessageStore
。它实现了MessageStore
和MessageGroupStore
接口。这个类可以作为构造函数参数接收MongoTemplate
,你可以使用它来配置自定义WriteConcern
。另一个构造函数需要MappingMongoConverter
和MongoDbFactory
,这允许你为Message
实例及其属性提供一些自定义转换。请注意,默认情况下,ConfigurableMongoDbMessageStore
使用标准的 Java 序列化来编写和读取与 MongoDB 之间的Message
实例(参见MongoDbMessageBytesConverter
),并依赖于MongoTemplate
中其他属性的默认值。它从提供的MongoDbFactory
和MappingMongoConverter
构建MongoTemplate
。由ConfigurableMongoDbMessageStore
存储的集合的默认名称是configurableStoreMessages
。当消息包含复杂的数据类型时,我们建议使用此实现来创建健壮且灵活的解决方案。
# MongoDB 通道消息存储
4.0 版引入了新的MongoDbChannelMessageStore
。它是一个优化的MessageGroupStore
,用于QueueChannel
实例。使用priorityEnabled = true
,你可以在<int:priority-queue>
实例中使用它来实现持久消息的优先级顺序轮询。Priority MongoDB 文档字段是从IntegrationMessageHeaderAccessor.PRIORITY
(priority
)消息头填充的。
此外,所有 MongoDBMessageStore
实例现在都有一个sequence
字段,用于MessageGroup
文档。sequence
值是对同一个集合中的简单sequence
文档执行$inc
操作的结果,该集合是按需创建的。在poll
操作中,当消息存储在相同的毫秒内时,sequence
字段用于提供先进先出消息顺序(如果进行了配置,则在优先级内)。
我们不建议对优先级和非优先级使用相同的MongoDbChannelMessageStore Bean,因为priorityEnabled 选项适用于整个存储,但是,同样的 collection 可以用于两种MongoDbChannelMessageStore 类型,由于存储中的消息轮询是经过排序的,并且使用 index.来配置该场景,因此可以从另一个扩展一个消息存储 Bean,如下例所示: |
---|
<bean id="channelStore" class="o.s.i.mongodb.store.MongoDbChannelMessageStore">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
<int:channel id="queueChannel">
<int:queue message-store="store"/>
</int:channel>
<bean id="priorityStore" parent="channelStore">
<property name="priorityEnabled" value="true"/>
</bean>
<int:channel id="priorityChannel">
<int:priority-queue message-store="priorityStore"/>
</int:channel>
# MongoDB 元数据存储
Spring Integration4.2 引入了一种新的基于 MongoDB 的MetadataStore
(参见元数据存储)实现。你可以使用MongoDbMetadataStore
在应用程序重新启动期间维护元数据状态。你可以将这个新的MetadataStore
实现与适配器一起使用,例如:
要指示这些适配器使用新的MongoDbMetadataStore
,请声明一个 Spring Bean,其 Bean 名称为metadataStore
。提要入站通道适配器自动拾取并使用声明的MongoDbMetadataStore
。下面的示例展示了如何声明名称为metadataStore
的 Bean:
@Bean
public MetadataStore metadataStore(MongoDbFactory factory) {
return new MongoDbMetadataStore(factory, "integrationMetadataStore");
}
MongoDbMetadataStore
还实现了ConcurrentMetadataStore
,使其在多个应用程序实例之间可靠地共享,其中只允许一个实例存储或修改键值。多亏了 MongoDB 的担保,所有这些操作都是原子操作。
# MongoDB 入站通道适配器
MongoDB 入站通道适配器是一个轮询使用者,它从 MongoDB 读取数据,并将其作为Message
有效负载发送。下面的示例展示了如何配置 MongoDB 入站通道适配器:
<int-mongodb:inbound-channel-adapter id="mongoInboundAdapter"
channel="replyChannel"
query="{'name' : 'Bob'}"
entity-class="java.lang.Object"
auto-startup="false">
<int:poller fixed-rate="100"/>
</int-mongodb:inbound-channel-adapter>
如前面的配置所示,你可以通过使用inbound-channel-adapter
元素并为各种属性提供值来配置 MongoDB 入站通道适配器,例如:
query
:一个 JSON 查询(参见MongoDB 查询 (opens new window))query-expression
:对 JSON 查询字符串(如上面的query
属性)或o.s.data.mongodb.core.query.Query
实例求值的 spel 表达式。与query
属性互斥。entity-class
:有效载荷对象的类型。如果不提供,则返回com.mongodb.DBObject
。collection-name
或collection-name-expression
:标识要使用的 MongoDB 集合的名称。mongodb-factory
:对o.s.data.mongodb.MongoDbFactory
实例的引用mongo-template
:对o.s.data.mongodb.core.MongoTemplate
实例的引用在所有其他入站适配器中通用的其他属性(例如“channel”)。
你不能同时设置mongo-template 和mongodb-factory 。 |
---|
前面的示例相对简单且静态,因为它具有query
的文本值,并使用collection
的默认名称。有时,你可能需要在运行时根据某些条件更改这些值。要做到这一点,使用它们的-expression
等价物(query-expression
和collection-name-expression
),其中提供的表达式可以是任何有效的 spel 表达式。
此外,你可能希望对从 MongoDB 读取的已成功处理的数据进行一些后处理。例如;你可能希望在文档被处理后移动或删除该文档。你可以通过使用添加的事务同步特性 Spring Integration2.2 来实现这一点,如下例所示:
<int-mongodb:inbound-channel-adapter id="mongoInboundAdapter"
channel="replyChannel"
query-expression="new BasicQuery('{''name'' : ''Bob''}').limit(100)"
entity-class="java.lang.Object"
auto-startup="false">
<int:poller fixed-rate="200" max-messages-per-poll="1">
<int:transactional synchronization-factory="syncFactory"/>
</int:poller>
</int-mongodb:inbound-channel-adapter>
<int:transaction-synchronization-factory id="syncFactory">
<int:after-commit
expression="@documentCleaner.remove(#mongoTemplate, payload, headers.mongo_collectionName)"
channel="someChannel"/>
</int:transaction-synchronization-factory>
<bean id="documentCleaner" class="thing1.thing2.DocumentCleaner"/>
<bean id="transactionManager" class="o.s.i.transaction.PseudoTransactionManager"/>
下面的示例显示了前面示例中引用的DocumentCleaner
:
public class DocumentCleaner {
public void remove(MongoOperations mongoOperations, Object target, String collectionName) {
if (target instanceof List<?>){
List<?> documents = (List<?>) target;
for (Object document : documents) {
mongoOperations.remove(new BasicQuery(JSON.serialize(document)), collectionName);
}
}
}
}
你可以使用transactional
元素将你的 Poller 声明为事务性的。这个元素可以引用一个真正的事务管理器(例如,如果流的其他部分调用了 JDBC)。如果没有“真实”事务,则可以使用o.s.i.transaction.PseudoTransactionManager
的实例,这是 Spring 的PlatformTransactionManager
的实现,并且在没有实际事务的情况下启用 Mongo 适配器的事务同步功能。
这样做不会使 MongoDB 本身具有事务性。 它允许在成功之前或之后(提交)或失败之后(回滚)进行操作的同步。 |
---|
一旦你的 Poller 是事务性的,你就可以在transactional
元素上设置o.s.i.transaction.TransactionSynchronizationFactory
的实例。aTransactionSynchronizationFactory
创建TransactionSynchronization
的实例。为了你的方便,我们公开了一个默认的基于 SPEL 的TransactionSynchronizationFactory
,它允许你配置 SPEL 表达式,其执行将与事务协调(同步)。支持用于 before-commit、after-commit 和 after-rollback 事件的表达式,以及用于发送计算结果(如果有的话)的每个事件的通道。对于每个子元素,你可以指定expression
和channel
属性。如果只存在channel
属性,则将接收到的消息作为特定同步场景的一部分发送到那里。如果只存在expression
属性,并且表达式的结果是非空值,则生成一条结果为有效负载的消息,并将其发送到默认通道(NullChannel
),并显示在日志中(在DEBUG
级别上)。如果你希望计算结果转到特定的通道,请添加channel
属性。如果表达式的结果是空的或无效的,则不会生成任何消息。
有关事务同步的更多信息,请参见事务同步。
从版本 5.5 开始,MongoDbMessageSource
可以配置为updateExpression
,它必须使用 MongoDBupdate
语法计算为String
,或者使用org.springframework.data.mongodb.core.query.Update
实例。它可以作为 ABEV 描述的后处理过程的替代方案,它修改了从集合中获取的那些实体,因此在下一个轮询周期中不会再次从集合中提取它们(假设更新更改了查询中使用的一些值)。仍然建议使用事务来实现执行隔离和数据一致性,当同一集合的MongoDbMessageSource
的几个实例在群集中使用时。
# MongoDB 更改入站通道适配器
从版本 5.3 开始,spring-integration-mongodb
模块引入了MongoDbChangeStreamMessageProducer
-用于 Spring dataMessageProducerSupport
API 的反应式MessageProducerSupport
实现。这个组件生成一个Flux
的消息,默认情况下以body
的ChangeStreamEvent
作为有效负载,并生成一些与流相关的更改头(参见MongoHeaders
)。建议将此MongoDbChangeStreamMessageProducer
与FluxMessageChannel
合并为outputChannel
,用于按需订阅和下游事件消费。
此通道适配器的 Java DSL 配置可能如下所示:
@Bean
IntegrationFlow changeStreamFlow(ReactiveMongoOperations mongoTemplate) {
return IntegrationFlows.from(
MongoDb.changeStreamInboundChannelAdapter(mongoTemplate)
.domainType(Person.class)
.collection("person")
.extractBody(false))
.channel(MessageChannels.flux())
.get();
}
当MongoDbChangeStreamMessageProducer
被停止,或者订阅在下游被取消,或者 MongoDB 变更流产生OperationType.INVALIDATE
时,Publisher
就完成了。可以再次启动通道适配器,并创建一个新的Publisher
源数据,并在MessageProducerSupport.subscribeToPublisher(Publisher<? extends Message<?>>)
中自动订阅它。如果需要使用来自其他地方的变更流事件,则可以重新配置此通道适配器,以便在两次启动之间提供新的选项。
有关变更流支持的更多信息,请参见 Spring Data MongoDB文件 (opens new window)。
# MongoDB 出站通道适配器
MongoDB 出站通道适配器允许你将消息有效负载写入 MongoDB 文档存储,如下例所示:
<int-mongodb:outbound-channel-adapter id="fullConfigWithCollectionExpression"
collection-name="myCollection"
mongo-converter="mongoConverter"
mongodb-factory="mongoDbFactory" />
如前面的配置所示,你可以通过使用outbound-channel-adapter
元素来配置 MongoDB 出站通道适配器,该元素为各种属性提供值,例如:
collection-name
或collection-name-expression
:标识要使用的 MongoDB 集合的名称。mongo-converter
:对o.s.data.mongodb.core.convert.MongoConverter
实例的引用,该实例有助于将原始 Java 对象转换为 JSON 文档表示。mongodb-factory
:引用o.s.data.mongodb.MongoDbFactory
的实例。mongo-template
:引用o.s.data.mongodb.core.MongoTemplate
的实例。注意:不能同时拥有 Mongo-Template 和 MongoDB-Factory 集。在所有其他入站适配器中通用的其他属性(例如“channel”)。
前面的示例相对简单且静态,因为它具有collection-name
的文本值。有时,你可能需要在运行时根据某些条件更改这个值。要做到这一点,请使用collection-name-expression
,其中提供的表达式是任何有效的 SPEL 表达式。
# MongoDB 出站网关
5.0 版引入了 MongoDB 出站网关。它允许你通过向数据库的请求通道发送消息来查询数据库。然后,网关将响应发送到应答通道。你可以使用消息有效负载和标题来指定查询和集合名称,如下例所示:
Java DSL
@SpringBootApplication
public class MongoDbJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MongoDbJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private MongoDbFactory;
@Autowired
private MongoConverter;
@Bean
public IntegrationFlow gatewaySingleQueryFlow() {
return f -> f
.handle(queryOutboundGateway())
.channel(c -> c.queue("retrieveResults"));
}
private MongoDbOutboundGatewaySpec queryOutboundGateway() {
return MongoDb.outboundGateway(this.mongoDbFactory, this.mongoConverter)
.query("{name : 'Bob'}")
.collectionNameFunction(m -> m.getHeaders().get("collection"))
.expectSingleResult(true)
.entityClass(Person.class);
}
}
Kotlin DSL
class MongoDbKotlinApplication {
fun main(args: Array<String>) = runApplication<MongoDbKotlinApplication>(*args)
@Autowired
lateinit var mongoDbFactory: MongoDatabaseFactory;
@Autowired
lateinit var mongoConverter: MongoConverter;
@Bean
fun gatewaySingleQueryFlow() =
integrationFlow {
handle(queryOutboundGateway())
channel { queue("retrieveResults") }
}
private fun queryOutboundGateway(): MongoDbOutboundGatewaySpec {
return MongoDb.outboundGateway(this.mongoDbFactory, this.mongoConverter)
.query("{name : 'Bob'}")
.collectionNameFunction<Any> { m -> m.headers["collection"] as String }
.expectSingleResult(true)
.entityClass(Person::class.java)
}
}
Java
@SpringBootApplication
public class MongoDbJavaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MongoDbJavaApplication.class)
.web(false)
.run(args);
}
@Autowired
private MongoDbFactory mongoDbFactory;
@Bean
@ServiceActivator(inputChannel = "requestChannel")
public MessageHandler mongoDbOutboundGateway() {
MongoDbOutboundGateway gateway = new MongoDbOutboundGateway(this.mongoDbFactory);
gateway.setCollectionNameExpressionString("'myCollection'");
gateway.setQueryExpressionString("'{''name'' : ''Bob''}'");
gateway.setExpectSingleResult(true);
gateway.setEntityClass(Person.class);
gateway.setOutputChannelName("replyChannel");
return gateway;
}
@Bean
@ServiceActivator(inputChannel = "replyChannel")
public MessageHandler handler() {
return message -> System.out.println(message.getPayload());
}
}
XML
<int-mongodb:outbound-gateway id="gatewayQuery"
mongodb-factory="mongoDbFactory"
mongo-converter="mongoConverter"
query="{firstName: 'Bob'}"
collection-name="myCollection"
request-channel="in"
reply-channel="out"
entity-class="org.springframework.integration.mongodb.test.entity$Person"/>
你可以在 MongoDB 出站网关中使用以下属性:
collection-name
或collection-name-expression
:标识要使用的 MongoDB 集合的名称。mongo-converter
:对o.s.data.mongodb.core.convert.MongoConverter
实例的引用,该实例有助于将原始 Java 对象转换为 JSON 文档表示。mongodb-factory
:引用o.s.data.mongodb.MongoDbFactory
的实例。mongo-template
:引用o.s.data.mongodb.core.MongoTemplate
的实例。注意:不能同时设置mongo-template
和mongodb-factory
。entity-class
:在 MongoTemplate 中传递给find(..)
和findOne(..)
方法的实体类的完全限定名。如果不提供此属性,则默认值为org.bson.Document
。query
或query-expression
:指定 MongoDB 查询。有关更多查询示例,请参见MongoDB 文档 (opens new window)。collection-callback
:引用org.springframework.data.mongodb.core.CollectionCallback
的实例。优选的实例是o.s.i.mongodb.outbound.MessageCollectionCallback
自 5.0.11 起带有请求消息上下文的实例。有关更多信息,请参见其 Javadocs。注意:不能同时拥有collection-callback
和任何查询属性。
作为query
和query-expression
属性的替代选项,你可以通过使用collectionCallback
属性作为对MessageCollectionCallback
功能接口实现的引用来指定其他数据库操作。下面的示例指定了一个 Count 操作:
private MongoDbOutboundGatewaySpec collectionCallbackOutboundGateway() {
return MongoDb.outboundGateway(this.mongoDbFactory, this.mongoConverter)
.collectionCallback((collection, requestMessage) -> collection.count())
.collectionName("myCollection");
}
# MongoDB 反应通道适配器
从版本 5.3 开始,提供了ReactiveMongoDbStoringMessageHandler
和ReactiveMongoDbMessageSource
实现。它们基于 Spring 数据中的ReactiveMongoOperations
,并且需要一个org.mongodb:mongodb-driver-reactivestreams
依赖项。
ReactiveMongoDbStoringMessageHandler
是ReactiveMessageHandler
的一种实现,当集成流定义中涉及到反应流组合时,它在框架中得到原生支持。有关更多信息,请参见reactiveMessageHandler。
从配置角度来看,与许多其他标准通道适配器没有区别。例如,对于 Java DSL,这样的通道适配器可以使用如下方式:
@Bean
public IntegrationFlow reactiveMongoDbFlow(ReactiveMongoDatabaseFactory mongoDbFactory) {
return f -> f
.channel(MessageChannels.flux())
.handle(MongoDb.reactiveOutboundChannelAdapter(mongoDbFactory));
}
在这个示例中,我们将通过提供的ReactiveMongoDatabaseFactory
连接到 MongoDB,并将来自请求消息的数据存储到具有data
名称的默认集合中。实际操作将通过内部创建的ReactiveStreamsConsumer
中的反应流组合按需执行。
该ReactiveMongoDbMessageSource
是基于所提供的ReactiveMongoDatabaseFactory
或ReactiveMongoOperations
和 MongoDB 查询(或表达式)的ReactiveMongoDbMessageSource
实现的AbstractMessageSource
,根据expectSingleResult
选项调用entityClass
或findOne()
的操作,用预期的entityClass
类型转换查询结果。当Publisher
(Flux
或Mono
根据expectSingleResult
选项)在产生的消息的有效负载被订阅时,按需执行查询执行和结果评估。当下游使用 Splitter 和FluxMessageChannel
时,框架可以自动订阅这样的有效负载(本质上是flatMap
)。否则,目标应用程序有责任在下游端点中订阅到已投票的发布程序。
使用 Java DSL,这样的通道适配器可以进行如下配置:
@Bean
public IntegrationFlow reactiveMongoDbFlow(ReactiveMongoDatabaseFactory mongoDbFactory) {
return IntegrationFlows
.from(MongoDb.reactiveInboundChannelAdapter(mongoDbFactory, "{'name' : 'Name'}")
.entityClass(Person.class),
c -> c.poller(Pollers.fixedDelay(1000)))
.split()
.channel(c -> c.flux("output"))
.get();
}
从版本 5.5 开始,ReactiveMongoDbMessageSource
可以配置为updateExpression
。它具有与阻塞MongoDbMessageSource
相同的功能。有关更多信息,请参见MongoDB 入站通道适配器和AbstractMongoDbMessageSourceSpec
Javadocs。