I have a working spring integration + rabbitmq application using xml config. Now, i am converting them to java config annotation. There are available classes and java annotation for some main amqp objects like Queue , TopicExchange , and Binding. However, I cant find any reference in converting inbound-gateway and outbound-gateway to java annotation or class implementation.
Here's my implementation:
// gateway.xml
<int-amqp:outbound-gateway request-channel="requestChannel" reply-channel="responseChannel" exchange-name="${exchange}" routing-key-expression="${routing}"/>
<int-amqp:inbound-gateway request-channel="inboundRequest"
queue-names="${queue}" connection-factory="rabbitConnectionFactory"
reply-channel="inboundResponse" message-converter="compositeMessageConverter"/>
Is it possible to convert them to java annotation or class implementation(bean, etc..)?
ADDITIONAL: I am currently using spring boot + spring integration.
Would be great, if you take a look into Spring Integration Java DSL.
It provides some fluent for AMQP:
#Bean
public IntegrationFlow amqpFlow() {
return IntegrationFlows.from(Amqp.inboundGateway(this.rabbitConnectionFactory, queue()))
.transform("hello "::concat)
.transform(String.class, String::toUpperCase)
.get();
}
#Bean
public IntegrationFlow amqpOutboundFlow() {
return IntegrationFlows.from(Amqp.channel("amqpOutboundInput", this.rabbitConnectionFactory))
.handle(Amqp.outboundAdapter(this.amqpTemplate).routingKeyExpression("headers.routingKey"))
.get();
}
From annotation perspective you should configure something like this using classes from Spring Integration directly:
#Bean
public AmqpInboundGateway amqpInbound() {
AmqpInboundGateway gateway = new AmqpInboundGateway(new SimpleMessageListenerContainer(this.rabbitConnectionFactory));
gateway.setRequestChannel(inboundChanne());
return gateway;
}
#Bean
#ServiceActivator(inputChannel = "amqpOutboundChannel")
public AmqpOutboundEndpoint amqpOutbound() {
AmqpOutboundEndpoint handler = new AmqpOutboundEndpoint(this.rabbitTemplate);
handler.setOutputChannel(amqpReplyChannel());
return handler;
}
Related
Does WebFlux Spring Boot #Transactional annotation work with reactive MongoDB?
I use WebFlux Spring Boot with reactive MongoDB like:
id 'org.springframework.boot' version '2.6.7'
...
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
...
I marked one of my method #Transactional to test. But it seems the annotation does not work for me. If an error occurs inside this method, then it still adds a raw to my mongoDB database.
import org.springframework.transaction.annotation.Transactional;
...
#Transactional
public Mono<Chat> createChat(Chat chat) {
return chatRepository
.save(chat)
.map(
c-> {
if (true) {
throw new RuntimeException();
}
return c;
});
}
Do I miss something or Spring Boot #Transactional annotation does not work with reactive MongoDB?
I use MongoDB v5.0.8
It seems like that Spring Data for reactive MongoDB requires to set explicitly a special bean transactionManager. As soon as I have added this bean to my configuration for the reactive MongoDB, the #Transactional annotation started working. So the example method posted in my question does not add a new raw to the database anymore if an error occurs inside the method.
Here is my configuration with transactionManager bean:
#Configuration
#EnableReactiveMongoRepositories
#AllArgsConstructor
public class ReactiveMongoConfiguration extends AbstractReactiveMongoConfiguration {
private final MongoProperties mongoProperties;
#Override
public MongoClient reactiveMongoClient() {
return MongoClients.create();
}
#Override
protected String getDatabaseName() {
return mongoProperties.getDatabase();
}
#Bean
ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory) {
return new ReactiveMongoTransactionManager(reactiveMongoDatabaseFactory);
}
P.S.
It turns out the defining of transactionManager bean is not enough to enable transactions in reactive MongoDB. The very server of MongoDB should be also configured with replication. I followed these steps and it worked for me.
I have a spring boot app, which uses resilience4j AOP-based #CircuitBreakers.
Now I would like to make the circuit breakers' information available in the /actuator/health endpoint, but I'm not seeing the details.circuitBtreakers objects described in the docs in the JSON output.
What am I doing wrong?
By comparison, getting dynamic cache information to appear in the /actuator/metrics endpoint required a small amount of custom wiring, but this is well documented. I wonder if there is a similar trick that I can apply for dynamically defined #CircuitBreakers to be registerd with the /actuator/health endpoint.
MyService.java:
#Service
public class MyService {
#Autowired
private CacheManager cacheManager;
#Autowired
private CacheMetricsRegistrar cacheMetricsRegistrar;
#PostConstruct
public void postConstruct() {
// On-the-fly defined (annotation-based) caches are not auto-registered with micrometer metrics.
final Cache cache = cacheManager.getCache("myCache");
cacheMetricsRegistrar.bindCacheToRegistry(cache);
}
#CircuitBreaker(name = "myCB", fallbackMethod = "fallbackCallAnApi")
public String callAnApi() throws RestClientException {
// ...
}
#Cacheable("myCache")
public String getSomethingCacheable() {
// ...
}
}
application.properties:
resilience4j.circuitbreaker.configs.default.registerHealthIndicator=true
management.endpoints.web.expose=health,metrics
management.endpoints.web.exposure.include=health,metrics
management.endpoint.health.enabled=true
management.endpoint.metrics.enabled=true
management.metrics.enable.resilience4j.circuitbreaker.calls=true
management.health.circuitbreakers.enabled=true
Dynamically registering CircuitBreakers for the HealthIndicator endpoint doesn't work at the moment.
Unfortunately you have to configure them:
resilience4j.circuitbreaker:
configs:
default:
registerHealthIndicator: true
instances:
myCB:
baseConfig: default
You could say it's a bug.
https://github.com/resilience4j/resilience4j/blob/master/resilience4j-spring-boot2/src/main/java/io/github/resilience4j/circuitbreaker/monitoring/health/CircuitBreakersHealthIndicator.java#L99-L102
I want to use JAXB annotations instead of Jackson's annotations for XML serialization and deserialization.
I'm using Spring Boot 2.1.3 which uses Spring 5.1.5 and Jackson 2.9.8.
So I defined my customizer bean
#Bean
Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
return (mapperBuilder) -> mapperBuilder
.modulesToInstall(new JaxbAnnotationModule())
.defaultUseWrapper(false);
}
which works automatically in Spring MVC #RestControllers.
However it does not apply to requests/responses made with a RestTemplate.
For the RestTemplate to work I had to define a special MappingJackson2XmlHttpMessageConverter bean.
#Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter(
Jackson2ObjectMapperBuilder builder) {
XmlMapper mapper = builder.createXmlMapper(true).build();
return new MappingJackson2XmlHttpMessageConverter(mapper);
}
Then, when the RestTemplate is needed I build it myself:
#Autowired
public AClient(RestTemplateBuilder restTemplateBuilder, MappingJackson2XmlHttpMessageConverter xmlHttpMessageConverter) {
this.xmlRestTemplate = restTemplateBuilder
.messageConverters(xmlHttpMessageConverter)
.build();
}
My problems with this approach are:
I have to define and autowire a second bean, how can I avoid the duplication of configuration?
The template I build is only valid for XML. I tried addMessageConverters but it yields weird errors with content negotiation.
In integration tests this means I have to mock the builder to create the same template to bind the mock MVC server to. This can get messy as soon as other template configurations pop up.
What I wish for: A single bean that provides a customizer and applies to Spring's MVC endpoints as well as the RestTemplateBuilder (replacing the default XmlHttpMessageConverter).
I've been looking at the Spring integration ip module, I wanted to create UDP channel for receiving, but I found I can only do it with XML.
I was thinking that I could make something out if I looked inside the implementation code, but it creates bean definition itself, from parameters supplied in xml.
I can't use xml definitions in my code, is there a way to make it work with spring without xml?
alternatively, is there any better way in java to work with udp?
Starting with version 5.0 there is Java DSL on the matter already, so the code for UDP Channel Adapters may look like:
#Bean
public IntegrationFlow inUdpAdapter() {
return IntegrationFlows.from(Udp.inboundAdapter(0))
.channel(udpIn())
.get();
}
#Bean
public QueueChannel udpIn() {
return new QueueChannel();
}
#Bean
public IntegrationFlow outUdpAdapter() {
return f -> f.handle(Udp.outboundAdapter(m -> m.getHeaders().get("udp_dest")));
}
But with existing Spring Integration version you can simply configure UnicastReceivingChannelAdapter bean:
#Bean
public UnicastReceivingChannelAdapter udpInboundAdapter() {
UnicastReceivingChannelAdapter unicastReceivingChannelAdapter = new UnicastReceivingChannelAdapter(1111);
unicastReceivingChannelAdapter.setOutputChannel(udpChannel());
return unicastReceivingChannelAdapter;
}
In the Reference Manual you can find the Tips and Tricks chapter for some info how to write Spring Integration application with raw Java and annotation configuration.
I added JIRA to address Java sample in the Reference Manual.
I am trying to convert a XML based configuration to JAVA based configuration. Can someone please let me know the java annotation based configuration for the following
<jms:outbound-channel-adapter channel="requestChannel"
connection-factory="testConnectionFactory"
destination-name="${jms.queueName}"
message-converter="messageConverter"/>
I tried having a look at this Reference doc. But i am not able to understand how do I map the above xml to the annotation config.
#ServiceActivator(inputChannel="requestChannel")
#Bean
public MessageHandler outbound(JmsTemplate jmsTemplate) {
JmsSendingMessageHandler handler = new JmsSendingMessageHandler(jmsTemplate);
handler.setDestinationName(...);
...
return handler;
}
#Bean
public JmsTemplate jmsTemplate(ConnectionFactory jmsConnectionFactory) {
...
template.setMessageConverter(converter());
return template;
}
Then add the connection factory and converter beans.
EDIT
Also pay attention to Spring Integration Java DSL project, which provides the org.springframework.integration.dsl.jms.Jms Factory on the matter. You can find its usage in the JmsTests: https://github.com/spring-projects/spring-integration-java-dsl/blob/master/src/test/java/org/springframework/integration/dsl/test/jms/JmsTests.java