Migration
From 6.x.x to 7.x.x
Change notes
- Upgrade to Spring Boot 4 and Jackson 3.
Actions
1. Update Jackson imports
If you have custom code using Jackson, update the imports from com.fasterxml.jackson.* to tools.jackson.*.
Before (Jackson 2):
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.core.type.TypeReference;
After (Jackson 3):
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.JsonNode;
import tools.jackson.core.type.TypeReference;
2. Remove CloudEvents Jackson dependency
If you were using CloudEvents, remove the cloudevents-json-jackson dependency as it only supports Jackson 2. A built-in module now provides Jackson 3 support for CloudEvents.
// Remove this dependency
implementation 'io.cloudevents:cloudevents-json-jackson:<version>'
From 5.x.x to 6.x.x
New features
- Connection customization: You can now customize the RabbitMQ connection by defining a
ConnectionFactoryCustomizerbean. For more details, see Customizing the connection.
@Bean
public ConnectionFactoryCustomizer connectionFactoryCustomizer() {
return (connectionFactory, asyncProps) -> {
connectionFactory.setExceptionHandler(new MyCustomExceptionHandler()); // Optional custom exception handler
connectionFactory.setCredentialsProvider(new MyCustomCredentialsProvider()); // Optional custom credentials provider
return connectionFactory;
};
}
Change notes
- The configuration property
listenRepliesfor RabbitMQ now defaults tonull. Previously, it wastrue, causing all applications to subscribe to a reply queue even when not needed. - The domain
appis now required. If not defined, the application will fail to start.
Actions
1. Configure listenReplies property
If your application uses the ReqReply pattern, you must explicitly set app.async.app.listenReplies to true. Otherwise, it should be false to avoid unnecessary resource usage.
YAML Configuration:
app:
async:
app:
listenReplies: true # set to true if ReqReply is required, false if not
Programmatic Configuration:
@Configuration
public class MyDomainConfig {
@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.listenReplies(Boolean.TRUE) // set to true if ReqReply is required, false if not
.build())
.build();
}
}
2. Define the app domain
The domain app must be defined in your configuration. Otherwise, the application will throw an exception at startup.
YAML Configuration:
app:
async:
app: # Configure the 'app' domain
# domain configuration goes here
Programmatic Configuration:
@Configuration
public class MyDomainConfig {
@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder() // Configure the 'app' domain
.connectionProperties(propertiesApp)
.build())
.build();
}
}
From 4.x.x to 5.x.x
New features
- Support for multiple brokers: It is now possible to configure and connect to up to two brokers simultaneously, using independent domains in the configuration.
Change notes
- Configuration properties are now defined per domain, allowing each to have its own properties and connection settings.
- The broker connection is no longer manually defined in the code. It is now automatically managed based on the
configuration declared in the
application.yamlfile or through programmatic configuration.
Actions
1. Update domain configuration structure
The app domain needs to be defined to specify the configuration properties.
Before:
app:
async:
withDLQRetry: true
maxRetries: 1
retryDelay: 1000
After:
app:
async:
app: # this is the name of the default domain
withDLQRetry: true
maxRetries: 1
retryDelay: 1000
2. Migrate connection configuration
Before:
The connection was defined manually in a Java class:
@Log4j2
@Configuration
@RequiredArgsConstructor
public class MyDomainConfig {
private final RabbitMQConnectionProperties properties;
private static final String TLS = "TLSv1.2";
private static final String FAIL_MSG = "Error creating ConnectionFactoryProvider in enroll";
@Primary
@Bean
public ConnectionFactoryProvider getConnectionFactoryProvider() {
final var factory = new ConnectionFactory();
var map = PropertyMapper.get();
map.from(properties::hostname).whenNonNull().to(factory::setHost);
map.from(properties::port).to(factory::setPort);
map.from(properties::username).whenNonNull().to(factory::setUsername);
map.from(properties::password).whenNonNull().to(factory::setPassword);
map.from(properties::ssl).whenTrue().as(isSsl -> factory).to(this::configureSsl);
return () -> factory;
}
private void configureSsl(ConnectionFactory factory) {
try {
var sslContext = SSLContext.getInstance(TLS);
var trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
factory.useSslProtocol(sslContext);
} catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
log.error("{}: {}", FAIL_MSG, e);
}
}
}
After:
The connection is configured directly in the application.yaml file per domain:
app:
async:
app: # this is the name of the default domain
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# Another domain can be configured with same properties structure that app
accounts: # this is a second domain name and can have another independent setup
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /accounts
Alternative - Programmatic Configuration:
Domains can also be configured programmatically:
@Configuration
public class MyDomainConfig {
@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
propertiesApp.setHost("localhost");
propertiesApp.setPort(5672);
propertiesApp.setVirtualHost("/");
propertiesApp.setUsername("guest");
propertiesApp.setPassword("guest");
RabbitProperties propertiesAccounts = new RabbitProperties();
propertiesAccounts.setHost("localhost");
propertiesAccounts.setPort(5672);
propertiesAccounts.setVirtualHost("/accounts");
propertiesAccounts.setUsername("guest");
propertiesAccounts.setPassword("guest");
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.build())
.withDomain("accounts", AsyncProps.builder()
.connectionProperties(propertiesAccounts)
.build())
.build();
}
}