@ManagedResource public class JdbcChannelMessageStore extends Object implements PriorityCapableChannelMessageStore, InitializingBean
Channel-specific implementation of
MessageGroupStore
using a relational
database via JDBC.
This message store shall be used for message channels only.
As such, the JdbcChannelMessageStore
uses database specific SQL queries.
Contrary to the JdbcMessageStore
, this implementation uses a single database table,
optimized to operate like a queue.
The SQL scripts for creating the table are packaged
under org/springframework/integration/jdbc/schema-*.sql
,
where *
denotes the target database type.
Modifier and Type | Field and Description |
---|---|
static String |
DEFAULT_REGION
Default region property, used to partition the message store.
|
static String |
DEFAULT_TABLE_PREFIX
Default value for the table prefix property.
|
Constructor and Description |
---|
JdbcChannelMessageStore()
Convenient constructor for configuration use.
|
JdbcChannelMessageStore(DataSource dataSource)
Create a
MessageStore
with all mandatory properties. |
Modifier and Type | Method and Description |
---|---|
void |
addAllowedPatterns(String... patterns)
Add patterns for packages/classes that are allowed to be deserialized.
|
MessageGroup |
addMessageToGroup(Object groupId,
Message<?> message)
Store a message in the database.
|
void |
afterPropertiesSet()
Check mandatory properties (
DataSource and
setChannelMessageStoreQueryProvider(ChannelMessageStoreQueryProvider) ). |
protected Message<?> |
doPollForMessage(String groupIdKey)
This method executes a call to the DB to get the oldest Message in the
MessageGroup which in the context of the
JdbcChannelMessageStore
means the channel identifier. |
MessageGroup |
getMessageGroup(Object groupId)
Not fully used.
|
int |
getMessageGroupCount()
Method not implemented.
|
protected MessageGroupFactory |
getMessageGroupFactory() |
protected String |
getQuery(org.springframework.integration.jdbc.store.JdbcChannelMessageStore.Query queryName,
java.util.function.Supplier<String> queryProvider)
Replace patterns in the input to produce a valid SQL query.
|
int |
getSizeOfIdCache()
Returns the size of the Message Id Cache, which caches Message Ids for
those messages that are currently being processed.
|
boolean |
isPriorityEnabled() |
int |
messageGroupSize(Object groupId)
Returns the number of messages persisted for the specified channel id (groupId)
and the specified region (
setRegion(String) ). |
Message<?> |
pollMessageFromGroup(Object groupId)
Polls the database for a new message that is persisted for the given
group id which represents the channel identifier.
|
void |
removeFromIdCache(String messageId)
Remove a Message Id from the idCache.
|
void |
removeMessageGroup(Object groupId)
Remove the message group with this id.
|
void |
setChannelMessageStoreQueryProvider(ChannelMessageStoreQueryProvider channelMessageStoreQueryProvider)
Sets the database specific
ChannelMessageStoreQueryProvider to use. |
void |
setDataSource(DataSource dataSource)
The JDBC
DataSource to use when interacting with the database. |
void |
setDeserializer(Deserializer<? extends Message<?>> deserializer)
A converter for deserializing byte arrays to messages.
|
void |
setJdbcTemplate(JdbcTemplate jdbcTemplate)
The
JdbcOperations
to use when interacting with the database. |
void |
setLobHandler(LobHandler lobHandler)
Override the
LobHandler that is used to create and unpack large objects in SQL queries. |
void |
setMessageGroupFactory(MessageGroupFactory messageGroupFactory)
Specify the
MessageGroupFactory to create MessageGroup object where
it is necessary. |
void |
setMessageRowMapper(MessageRowMapper messageRowMapper)
Allows for passing in a custom
MessageRowMapper . |
void |
setPreparedStatementSetter(ChannelMessageStorePreparedStatementSetter preparedStatementSetter)
Set a
ChannelMessageStorePreparedStatementSetter to insert message into the database. |
void |
setPriorityEnabled(boolean priorityEnabled) |
void |
setRegion(String region)
A unique grouping identifier for all messages persisted with this store.
|
void |
setSerializer(Serializer<? super Message<?>> serializer)
A converter for serializing messages to byte arrays for storage.
|
void |
setTablePrefix(String tablePrefix)
Public setter for the table prefix property.
|
void |
setUsingIdCache(boolean usingIdCache)
Consider using this property when polling the database transactionally
using multiple parallel threads, meaning when the configured poller is configured
using a task executor.
|
public static final String DEFAULT_REGION
public static final String DEFAULT_TABLE_PREFIX
public JdbcChannelMessageStore()
public JdbcChannelMessageStore(DataSource dataSource)
MessageStore
with all mandatory properties. The passed-in
DataSource
is used to instantiate a JdbcTemplate
with JdbcTemplate.setFetchSize(int)
set to 1
and with JdbcTemplate.setMaxRows(int)
set to 1
.dataSource
- a DataSource
public void setDataSource(DataSource dataSource)
DataSource
to use when interacting with the database.
The passed-in DataSource
is used to instantiate a JdbcTemplate
with JdbcTemplate.setFetchSize(int)
set to 1
and with JdbcTemplate.setMaxRows(int)
set to 1
.dataSource
- a DataSource
public void setDeserializer(Deserializer<? extends Message<?>> deserializer)
deserializer
- the deserializer to setpublic void addAllowedPatterns(String... patterns)
com.foo.*
, *.MyClass
.patterns
- the patterns.public void setJdbcTemplate(JdbcTemplate jdbcTemplate)
JdbcOperations
to use when interacting with the database. Either
this property can be set or the dataSource
.
Please consider passing in a JdbcTemplate
with a fetchSize property
of 1. This is particularly important for Oracle to ensure First In, First Out (FIFO)
message retrieval characteristics.jdbcTemplate
- a JdbcOperations
public void setLobHandler(LobHandler lobHandler)
LobHandler
that is used to create and unpack large objects in SQL queries. The default is
fine for almost all platforms, but some Oracle drivers require a native implementation.lobHandler
- a LobHandler
public void setMessageRowMapper(MessageRowMapper messageRowMapper)
MessageRowMapper
. The MessageRowMapper
is used to convert the selected database row representing the persisted
message into the actual Message
object.messageRowMapper
- Must not be nullpublic void setPreparedStatementSetter(ChannelMessageStorePreparedStatementSetter preparedStatementSetter)
ChannelMessageStorePreparedStatementSetter
to insert message into the database.preparedStatementSetter
- ChannelMessageStorePreparedStatementSetter
to use.
Must not be nullpublic void setChannelMessageStoreQueryProvider(ChannelMessageStoreQueryProvider channelMessageStoreQueryProvider)
ChannelMessageStoreQueryProvider
to use.
The JdbcChannelMessageStore
provides the SQL queries to retrieve messages from
the database. See the JavaDocs ChannelMessageStoreQueryProvider
(all known
implementing classes) to see those implementations provided by the framework.
You can provide your own query implementations, if you need to support additional databases and/or need to fine-tune the queries for your requirements.
channelMessageStoreQueryProvider
- Must not be null.public void setRegion(String region)
DEFAULT_REGION
.region
- the region name to setpublic void setSerializer(Serializer<? super Message<?>> serializer)
serializer
- The serializer to setpublic void setTablePrefix(String tablePrefix)
DEFAULT_TABLE_PREFIX
.tablePrefix
- the tablePrefix to setpublic void setUsingIdCache(boolean usingIdCache)
Consider using this property when polling the database transactionally using multiple parallel threads, meaning when the configured poller is configured using a task executor.
The issue is that the pollMessageFromGroup(Object)
looks for the
oldest entry for a giving channel (groupKey) and region (setRegion(String)
).
If you do that with multiple threads and you are using transactions, other
threads may be waiting for that same locked row.
If using the provided
OracleChannelMessageStoreQueryProvider
,
don't set usingIdCache
to true, as the Oracle query will ignore locked rows.
Using the id cache, the JdbcChannelMessageStore
will store each
message id in an in-memory collection for the duration of processing. With
that, any polling threads will explicitly exclude those messages from
being polled.
For this to work, you must setup the corresponding
TransactionSynchronizationFactory
:
<int:transaction-synchronization-factory id="syncFactory">
<int:after-commit expression="@jdbcChannelMessageStore.removeFromIdCache(headers.id.toString())" />
<int:after-rollback expression="@jdbcChannelMessageStore.removeFromIdCache(headers.id.toString())" />
</int:transaction-synchronization-factory>
This TransactionSynchronizationFactory
is then referenced in the
transaction configuration of the poller:
<int:poller fixed-delay="300" receive-timeout="500"
max-messages-per-poll="1" task-executor="pool">
<int:transactional propagation="REQUIRED" synchronization-factory="syncFactory"
isolation="READ_COMMITTED" transaction-manager="transactionManager" />
</int:poller>
usingIdCache
- When true
the id cache will be used.public void setPriorityEnabled(boolean priorityEnabled)
public boolean isPriorityEnabled()
isPriorityEnabled
in interface PriorityCapableChannelMessageStore
public void setMessageGroupFactory(MessageGroupFactory messageGroupFactory)
MessageGroupFactory
to create MessageGroup
object where
it is necessary.
Defaults to SimpleMessageGroupFactory
.messageGroupFactory
- the MessageGroupFactory
to use.protected MessageGroupFactory getMessageGroupFactory()
public void afterPropertiesSet()
DataSource
and
setChannelMessageStoreQueryProvider(ChannelMessageStoreQueryProvider)
). If no MessageRowMapper
and ChannelMessageStorePreparedStatementSetter
was explicitly set using
setMessageRowMapper(MessageRowMapper)
and
setPreparedStatementSetter(ChannelMessageStorePreparedStatementSetter)
respectively, the default
MessageRowMapper
and ChannelMessageStorePreparedStatementSetter
will be instantiate using the
specified deserializer
and lobHandler
.
Also, if the jdbcTemplate's fetchSize property (JdbcTemplate.getFetchSize()
)
is not 1, a warning will be logged. When using the JdbcChannelMessageStore
with Oracle, the fetchSize value of 1 is needed to ensure FIFO characteristics
of polled messages. Please see the Oracle ChannelMessageStoreQueryProvider
for more details.afterPropertiesSet
in interface InitializingBean
public MessageGroup addMessageToGroup(Object groupId, Message<?> message)
addMessageToGroup
in interface BasicMessageGroupStore
groupId
- the group id to store the message undermessage
- a messagepublic MessageGroup getMessageGroup(Object groupId)
getMessageGroup
in interface BasicMessageGroupStore
groupId
- The group identifier.@ManagedAttribute public int getMessageGroupCount()
UnsupportedOperationException
- Method not supported.protected String getQuery(org.springframework.integration.jdbc.store.JdbcChannelMessageStore.Query queryName, java.util.function.Supplier<String> queryProvider)
queryName
- The Query
to be transformed.queryProvider
- a supplier to provide the query template.@ManagedAttribute public int messageGroupSize(Object groupId)
setRegion(String)
).messageGroupSize
in interface BasicMessageGroupStore
groupId
- The group identifier.public void removeMessageGroup(Object groupId)
BasicMessageGroupStore
removeMessageGroup
in interface BasicMessageGroupStore
groupId
- The id of the group to remove.public Message<?> pollMessageFromGroup(Object groupId)
pollMessageFromGroup
in interface BasicMessageGroupStore
groupId
- The group identifier.protected Message<?> doPollForMessage(String groupIdKey)
JdbcChannelMessageStore
means the channel identifier.groupIdKey
- String representation of message group (Channel) IDpublic void removeFromIdCache(String messageId)
Remove a Message Id from the idCache. Should be used in conjunction with the Spring Integration Transaction Synchronization feature to remove a message from the Message Id cache once a transaction either succeeded or rolled back.
Only applicable if setUsingIdCache(boolean)
is set to
true
messageId
- The message identifier.@ManagedMetric public int getSizeOfIdCache()