Skip to content

Spring Integration 6.x to 7.0 Migration Guide

Glenn Renfro edited this page Oct 22, 2025 · 15 revisions

New DistributedLock API

Spring Integration 7.0 introduces a DistributedLock abstraction with a Time-To-Live (TTL) API (for now), allowing lock objects in the target persistent store to be marked as expired if the instances holding the lock become unresponsive. This enables other instances to acquire the lock. With this new abstraction, the LockRegistry interface—along with its extensions and implementations—now accepts a generic argument to specify the Lock implementation provided by that particular LockRegistry. For example, the DefaultLockRegistry is now defined as: public final class DefaultLockRegistry implements LockRegistry<Lock>. Similarly, ZookeeperLockRegistry is now: public class ZookeeperLockRegistry implements ExpirableLockRegistry<Lock>. However, JdbcLockRegistry and RedisLockRegistry are now defined as:

implements ExpirableLockRegistry<DistributedLock>, RenewableLockRegistry<DistributedLock>

Therefore, the obtain() method in these registries now returns a DistributedLock instance, which includes the newly introduced lock(Duration ttl) and tryLock(Duration waitTime, Duration ttl) methods.

The RedisLockRegistry has supported TTL from the beginning via its default expireAfter property. However, with the addition of lock(Duration ttl), TTL can now be specified per lock usage.

The JdbcLockRegistry, being RDBMS-based, required changes to the SQL schema. A new EXPIRED_AFTER column has been added to the INT_LOCK table. As a result, for existing databases, the following DDL statement must be executed to properly migrate to Spring Integration 7.0:

ALTER TABLE INT_LOCK ADD EXPIRED_AFTER TIMESTAMP NOT NULL;

Removal of deprecated classes from spring-integration-hazelcast

Due to the removal of the CP Subsystem from the open-source edition of Hazelcast, the related Spring Integration classes were deprecated in version 6.5. These classes are now fully removed as outdated APIs. For more information, see the Spring Integration 6.4 to 6.5 Migration Guide.

Deprecated JUnit 4 Based Components

The classes in spring-integration-test-support module to support JUnit 4 infrastructure, such as Log4j2LevelAdjuster, AbstractRequestResponseScenarioTests, LongRunningIntegrationTest and SingleRequestResponseScenarioTests, are now deprecated in favor of respective replacements for JUnit Jupiter. Their JavaDocs have references to replacements.

Jackson 3 support

Spring Integration now provides classes and injection points for Jackson 3 support. Jackson 2 based classes have been deprecated for removal. See their JavaDocs for migration path. Some defaults in Jackson 3 are not compatible with Jackson 2. So, if you find your application not working, consider injecting custom Jackson 3 ObjectMapper with the respective features set/unset. For example, so far we have noticed these discrepancies:

  • WRITE_DATES_AS_TIMESTAMPS(false) // was true in 2.x
  • WRITE_DURATIONS_AS_TIMESTAMPS(false) // was true in 2.x
  • ONE_BASED_MONTHS(true) // was false in 2.x

TcpListener.onMessage() contract

The TcpListener.onMessage() has had a boolean return contract for many years without any use in the framework. Now the return type has been changed to void to simplify contract and all the logic in the framework where this method is involved.

Migration to Spring Core Retry

The spring-retry dependency, together with all of its API usage has been replaced by Core Spring Resilience Features(retry API) in Spring Framework Core module. This breaking change is the natural evolution of the whole Spring portfolio. The Spring Retry project is in maintenance mode for now without any further major/minor version plans. Everyone is encouraged to migrate to the retry API in Spring Framework. In general, the following references have been migrated (and therefore, must be fixed in the target projects which uses Spring Integration):

  • org.springframework.retry.support.RetryTemplate -> org.springframework.core.retry.RetryTemplate
  • org.springframework.retry.RetryPolicy -> org.springframework.core.retry.RetryPolicy
  • org.springframework.retry.RecoveryCallback -> org.springframework.integration.core.RecoveryCallback There is no RecoveryCallback abstraction in the Spring Framework, since a regular try..catch on the RetryException is enough. For Spring Integration, the RecoveryCallback makes sense as a dead-letter publisher to an error channel.
  • org.springframework.retry.backoff.BackOffPolicy -> org.springframework.util.backoff.BackOff However, it is not exposed directly as a RetryTemplate options: rather as an internal API backed by configuration via the RetryPolicy.Builder.
  • The RetryContext in AMPQ, JMS and Apache Kafka channel adapters is replaced with an internal AttributeAccessor implementation.

Therefore, the following project classes have breaking changes:

  • AmqpBaseInboundChannelAdapterSpec
  • AmqpBaseInboundGatewaySpec
  • AmqpInboundChannelAdapter
  • AmqpInboundGateway
  • PostgresSubscribableChannel
  • ChannelPublishingJmsMessageListener
  • JmsInboundGatewaySpec
  • JmsMessageDrivenChannelAdapterSpec
  • KafkaInboundGatewaySpec
  • KafkaMessageDrivenChannelAdapterSpec
  • KafkaInboundEndpoint
  • KafkaInboundGateway
  • KafkaMessageDrivenChannelAdapter

The RetryTemplate and RecoveryCallback configuration options of these classes now require org.springframework.core.retry.RetryTemplate and org.springframework.integration.core.RecoveryCallback, respectively. The ThreadLocal<@Nullable AttributeAccessor> ATTRIBUTES_HOLDER is still there, however it comes with limited number of attributes (mostly related to the endpoint logic) since new RetryTemplate implementation does not expose a RetryContext abstraction.

The RequestHandlerRetryAdvice was rebuilt to avoid external API as much as possible. For the stateless retry logic, there is just enough to provide a org.springframework.core.retry.RetryPolicy. The stateful retry logic is activated by the Function<Message<?>, Object> stateKeyFunction. The RetryStateGenerator abstraction and its SpelExpressionRetryStateGenerator implementation have been removed due to dependency on the spring-retry API. So, the RequestHandlerRetryAdvice in new the incarnation does not expect a RetryTemplate and RetryStateGenerator. Instead, the org.springframework.core.retry.RetryPolicy can be set: by default, 3 retry attempts with no delay in between. This RetryPolicy is used internally by the org.springframework.core.retry.RetryTemplate for stateless logic, and directly with its BackOff API for stateful. The stateKeyFunction together with a Predicate<Message<?>> newMessagePredicate replaces RetryStateGenerator. In addition, the stateCacheSize (default 100) can be modified to control the cache size for the stateful state objects. Another new option is an org.springframework.core.retry.RetryListener injection.

Rename MESSAGE_BYTES SQL column to MESSAGE_CONTENT

The MESSAGE_BYTES column in the INT_MESSAGE and INT_CHANNEL_MESSAGE tables of the SQL schemas for message stores has been renamed to the MESSAGE_CONTENT since the serialized message form might not always be just a bytes array. Therefore, respective DDL has to be applied to existing database schemas:

ALTER TABLE INT_MESSAGE RENAME COLUMN MESSAGE_BYTES TO MESSAGE_CONTENT;
ALTER TABLE INT_CHANNEL_MESSAGE RENAME COLUMN MESSAGE_BYTES TO MESSAGE_CONTENT;

Module packages standardization

All the modules in the project now follow the standard package structure. The components for inbound and interactions now have been moved to the input and output packages, respectively. For example, the org.springframework.integration.file.FileWritingMessageHandler class is now in the org.springframework.integration.file.outbound.FileWritingMessageHandler. The classes in previous locations are marked as deprecated for removal. The Java DSL and XML parsers now use new classes. An injection of those deprecated classes might cause "bean not found" error since Java DSL and XML now populate new classes. Therefore, target projects should respond respectively for the deprecation warnings on compilation.

Clone this wiki locally