I want to rewrite this Spring AMQP code without annotations:
#SpringBootApplication
public class So51009346Application {
public static final String QUEUE_PROCESSING_TRANSACTION = "q1";
public static void main(String[] args) {
SpringApplication.run(So51009346Application.class, args);
}
#Bean
public ApplicationRunner runner(RabbitTemplate template) {
return args -> {
ReplyObject reply = (ReplyObject) template.convertSendAndReceive("ex", "rk", new RequestObject());
System.out.println(reply);
};
}
#Bean
public SimpleMessageListenerContainer container(ConnectionFactory cf, Listener listener) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cf);
container.setQueueNames(QUEUE_PROCESSING_TRANSACTION);
container.setMessageListener(new MessageListenerAdapter(listener, "process"));
return container;
}
#Bean
public Queue queue() {
return new Queue(QUEUE_PROCESSING_TRANSACTION);
}
#Bean
public TopicExchange te() {
return new TopicExchange("ex");
}
#Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(te()).with("rk");
}
}
class RequestObject implements Serializable {
private static final long serialVersionUID = 1L;
}
class ReplyObject implements Serializable {
private static final long serialVersionUID = 1L;
}
#Component
class Listener {
public ReplyObject process(RequestObject ro) {
return new ReplyObject();
}
}
I tried this simple Java code without annotations:
Producer code:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.plugin.database.bean.TransactionsBean;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
#WebListener
public class ContextServer implements ServletContextListener {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
Connection connection = connectionFactory.createConnection();
AmqpAdmin admin = new RabbitAdmin(connectionFactory);
admin.declareExchange(new TopicExchange(EXCHANGE_PROCESSING));
admin.declareQueue(new Queue(QUEUE_PROCESSING_TRANSACTION, false));
admin.declareBinding(BindingBuilder.bind(new Queue(QUEUE_PROCESSING_TRANSACTION, false)).to(new TopicExchange(EXCHANGE_PROCESSING)).with(ROUTING_KEY_PROCESSING_TRANSACTION));
RabbitTemplate template = new RabbitTemplate(connectionFactory);
TransactionsBean obj = new TransactionsBean();
obj.setMerchant_id(232323);
template.setReplyTimeout(600000);
TransactionsBean reply = (TransactionsBean) template.convertSendAndReceive(EXCHANGE_PROCESSING, ROUTING_KEY_PROCESSING_TRANSACTION, obj);
System.out.println("!!!!! Received Transaction_id " + reply.getTransaction_id());
#Override
public final void contextDestroyed(final ServletContextEvent sce) {
}
}
Consumer code:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.plugin.database.bean.TransactionsBean;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
#SpringBootApplication
#WebListener
public class ContextServer implements ServletContextListener {
private static String QUEUE_PROCESSING_TRANSACTION = "processing-process-queue";
private static final String EXCHANGE_PROCESSING = "processing";
private static final String ROUTING_KEY_PROCESSING_TRANSACTION = "processing.trx.process";
#Override
public final void contextInitialized(final ServletContextEvent contextEvent) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
AmqpAdmin admin = new RabbitAdmin(connectionFactory);
admin.declareExchange(new TopicExchange(EXCHANGE_PROCESSING));
admin.declareQueue(new Queue(QUEUE_PROCESSING_TRANSACTION, false));
admin.declareBinding(BindingBuilder.bind(new Queue(QUEUE_PROCESSING_TRANSACTION, false))
.to(new TopicExchange(EXCHANGE_PROCESSING)).with(ROUTING_KEY_PROCESSING_TRANSACTION));
RabbitTemplate template = new RabbitTemplate(connectionFactory);
}
#Bean
public SimpleMessageListenerContainer container(ConnectionFactory cf, Listener listener) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cf);
container.setQueueNames(QUEUE_PROCESSING_TRANSACTION);
container.setMessageListener(new MessageListenerAdapter(listener, "process"));
container.setMessageConverter(new SerializerMessageConverter());//basic converter for java.io.Serializable POJO
return container;
}
#Override
public final void contextDestroyed(final ServletContextEvent sce) {
}
#Component
class Listener {
public TransactionsBean process(TransactionsBean ro) {
TransactionsBean obj = new TransactionsBean();
obj.setTransaction_id("some_id");
return obj;
}
}
}
Error stack:
13:20:44,797 INFO [org.springframework.amqp.rabbit.listener.DirectReplyToMessageListenerContainer] (ServerService Thread Pool -- 79) Container initialized for queues: [amq.rabbitmq.reply-to]
13:20:44,803 INFO [org.springframework.amqp.rabbit.listener.DirectReplyToMessageListenerContainer] (ServerService Thread Pool -- 79) SimpleConsumer [queue=amq.rabbitmq.reply-to, consumerTag=amq.ctag-oWxWZJEPgZyP-gRxWe-Ifg identity=42eb5972] started
13:20:49,846 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 79) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./rest_api: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./rest_api: java.lang.RuntimeException: java.lang.NullPointerException
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:81)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:514)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.jboss.threads#2.3.1.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads#2.3.1.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads#2.3.1.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads#2.3.1.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.base/java.lang.Thread.run(Thread.java:844)
at org.jboss.threads#2.3.1.Final//org.jboss.threads.JBossThread.run(JBossThread.java:485)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at io.undertow.servlet//io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:251)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:96)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:78)
... 8 more
Caused by: java.lang.NullPointerException
at deployment.rest_api.war//org.rest.api.context.ContextServer.contextInitialized(ContextServer.java:43)
at io.undertow.servlet//io.undertow.servlet.core.ApplicationListeners.contextInitialized(ApplicationListeners.java:187)
at io.undertow.servlet//io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:215)
at io.undertow.servlet//io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:184)
at io.undertow.servlet//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1526)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1526)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1526)
at org.wildfly.extension.undertow//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1526)
at io.undertow.servlet//io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:249)
... 10 more
13:20:49,885 ERROR [org.jboss.as.controller.management-operation] (DeploymentScanner-threads - 2) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "rest_api.war")]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.undertow.deployment.default-server.default-host./rest_api" => "java.lang.RuntimeException: java.lang.NullPointerException
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
Caused by: java.lang.NullPointerException"}}
13:20:49,908 INFO [org.jboss.as.server] (DeploymentScanner-threads - 2) WFLYSRV0010: Deployed "rest_api.war" (runtime-name : "rest_api.war")
Message from Producer is successfully send.
I get NPE at this line in Producer: reply.getTransaction_id()
What is the proper way to implement the Consumer without annotations with basic Java code?
As I explained in my answer to your previous question, if you are not familiar with Spring, the best way to get started is to use Spring Boot. Go to http://start.spring.io and build a new project after selecting RabbitMQ as a dependency. That is exactly what I did for the example code there.
If you insist on rolling your own code and not using Spring to manage the dependencies and lifecycles of these components; you need to do that work yourself - calling afterPropertiesSet(), start() etc.
I get NPE
That is entirely insufficient information. You need to show the complete stack trace, and all of your code, including the TransactionsBean.
Trust me; "without annotations" means you have to write a lot more code yourself.
EDIT
System.out.println(" !!!!!!!! Transaction_id " + receivedobj.getTransaction_id());
Of course you'll get an NPE - you don't actually check the returned object is not null; the template has a default reply timeout of 5 seconds, after which null is returned.
The container won't do anything until it is start()ed; again; please learn to use Spring to manage the lifecycle of these objects.
There multiple problems here:
As mentioned above by #Gary Russell there is no connection timeout at first
The root problem of receiving null is that convertSendAndReceive operate with POJO which should be serializable and Serializer should be described on Consumer side:
#Bean
public SimpleMessageListenerContainer container(ConnectionFactory cf, Listener listener) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cf);
container.setQueueNames(QUEUE_PROCESSING_TRANSACTION);
container.setMessageListener(new MessageListenerAdapter(listener, "process"));
container.setMessageConverter(new SerializerMessageConverter());//basic converter for java.io.Serializable POJO
return container;
}
Related
I am trying to create a Generic eventPublisher for my microservices.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
#EnableBinding(TaskEventStreams.class)
public class EventPublisher {
private final TaskEventStreams source;
#Autowired
public EventPublisher(TaskEventStreams source) {
this.source = source;
}
public void publishEvent(BaseEvent event) {
publishEvent(event, event.getTenant());
}
public void publishEvent(BaseEvent event, String key) {
source.taskEventOutput().send(
MessageBuilder
.withPayload(event)
.copyHeaders(event.getHeaders())
.setHeader("partitionKey", key)
.build());
}
}
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
public interface TaskEventStreams {
String TASK_EVENT_OUTPUT = "task-event-output";
#Output(TASK_EVENT_OUTPUT)
MessageChannel taskEventOutput();
}
Application properties
spring:
cloud:
stream:
default-binder: kafka
kafka:
binder:
brokers: localhost:9092
auto-create-topics: true
bindings:
task-event-output:
destination: tasks
group: tasks
binder: kafka
contentType: application/json
This service will only publish the events. These events then later can be consumed by other services. But when I am trying to publish the event I am getting below exception
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Main {
#Autowired
EventPublisher eventPublisher;
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
System.out.println("Hello world!");
}
#PostConstruct
public void init() {
BaseEvent event = TaskCreatedEvent.builder().tenant("tenant").build();
eventPublisher.publishEvent(event);
}
}
Exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'main': Invocation of init method failed; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'task-event-output'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers, failedMessage=GenericMessage [payload=byte[255], headers={id=06b61f95-24d8-7f35-3e57-9ae262c2ca47, partitionKey=tenant, contentType=application/json, tenant=tenant, timestamp=1675063077441}], failedMessage=GenericMessage [payload=byte[255], headers={id=06b61f95-24d8-7f35-3e57-9ae262c2ca47, partitionKey=tenant, contentType=application/json, tenant=tenant, timestamp=1675063077441}]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor
Is there a limitation that without consumer we cannot have producer? or am I missing something with this
#PostConstruct
public void init() {
BaseEvent event = TaskCreatedEvent.builder().tenant("tenant").build();
eventPublisher.publishEvent(event);
}
That's too early to interact with low-level resource. You really cannot send message to the broker while your application is still in a configuration phase.
See into an ApplicationRunner instead: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.spring-application.command-line-runner
Im setting up the connection factory for my rabbitmq application. Ive got the beans created in the config, however for some reason the ConnectionFactory that ive passed into the RabbitTemplate doesnt seem to be creating the bean automatically as it should.
the error its saying is Could not autowire. No beans of 'ConnectionFactory' type found.
However this bean should be created automatically. It works if i create a bean of ConnectionFactory manually, but struggling to understand why it doesnt work without it.
package com.example.redistorabbit;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class RedisToRabbitApplication {
public static void main(String[] args) {
SpringApplication.run(RedisToRabbitApplication.class, args);
}
public static final String TOPIC_EXCHANGE_NAME = "covid-exchange";
public static final String QUEUE_NAME = "cases-entity";
#Bean
Queue queue(){
return new Queue(QUEUE_NAME,false);
}
#Bean
TopicExchange exchange(){
return new TopicExchange(TOPIC_EXCHANGE_NAME);
}
#Bean
Binding binding(Queue queue, TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with("#");
}
#Bean
public RabbitTemplate publishingRabbitTemplate(final ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonConverter());
rabbitTemplate.setChannelTransacted(true);
return rabbitTemplate;
}
#Bean
public Jackson2JsonMessageConverter jsonConverter() {
return new Jackson2JsonMessageConverter();
}
}
another issue i seem to have is even though i have the Jackson2JsonMessageConverter when the lisetener received and prints the message it is showing as bytes instead of a json message:
#Component
#RequiredArgsConstructor
public class Receiver {
private final CasesRepository casesRepository;
private static final Logger log = LoggerFactory.getLogger(Receiver.class);
#RabbitListener(queues = RedisToRabbitApplication.QUEUE_NAME)
public void consumeMessage(final Message message) {
log.info("received: " + message.toString());
}
}
received: (Body:'[B#1b68f46c(byte[91])'
Have you tried Injecting the Spring Object Mapper into the Jackson Message converter?
#Bean
public Jackson2JsonMessageConverter jsonConverter(ObjectMapper objectMapper) {
return new Jackson2JsonMessageConverter(objectMapper);
}
It seems the issue is with the version of spring-boot-autoconfiguration dependency, i could see the bean in the version for 2.7.3, in the JacksonAutoConfiguration class, however Intellij was still saying no bean was found. I added the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.5.15.RELEASE</version>
</dependency>
and both ConnectionFactory and ObjectMapper beans have been created automatically
I want to create a daily background job to be executed by AEM.
I read an aem document and apache sling official site, and I thought I need two classes.
a service class that register the job to JobManager.
a consumer class that do the job.
So I tried these code, but my job was not executed.
service class
import org.apache.sling.event.jobs.JobManager;
import org.apache.sling.event.jobs.JobBuilder.ScheduleBuilder;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component
public class MyJobService {
private static final Logger logger = LoggerFactory.getLogger(MyJobService.class);
#Reference
private JobManager jobManager;
public static final String JOB_TOPIC = "my/sample/jobtopic";
public void startScheduledJob() {
ScheduleBuilder scheduleBuilder = jobManager.createJob(JOB_TOPIC).schedule();
scheduleBuilder.hourly(9, 0); // execute daily at AM9:00
if (scheduleBuilder.add() == null) {
logger.error("myjobservice error");
}
}
}
job consumer class
import org.apache.sling.event.jobs.Job;
import org.apache.sling.event.jobs.consumer.JobConsumer;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Component(
immediate = true,
service = JobConsumer.class,
property = {
JobConsumer.PROPERTY_TOPICS + "=my/sample/jobtopic"
}
)
public class MyJobConsumer implements JobConsumer {
private static final Logger logger = LoggerFactory.getLogger(MyJobConsumer.class);
#Override
public JobResult process(Job job) {
String topic = job.getTopic();
logger.info("this message is from myjobconsumer. topic is " + topic);
return JobResult.OK;
}
}
Do I need another class or some configurations? Does My code have something wrong?
If you annotate a method with #Activate it will be called when the component starts.
#Activate
public void startScheduledJob()
I guess you want your job to run on startup.
Another option would be to let MyJobService be a servlet and call it from outside.
I am learning about ActiveMQ, and so far I have made a simple Spring Boot producer+consumer application (call it App1 for the purposes of this question) that communicates with a local instance of ActiveMQ and everything works as expected.
Now I am trying to run a different Spring Boot application (on the same computer but after ensuring App1 is not running) that has only a consumer (no producer), but when I start up this application, the messages in the queue (that I put using a modified App1 in which I removed the consumer portion of the application) do not get picked up. In App1, as soon as the message was published, the consumer printed out the system.out print statement, but not so in this consumer-only application. Below is my listener component class:
package com.demo.listener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
#Component
public class Consumer {
#JmsListener(destination = "testqueue")
public void consume(String message) {
System.out.println("Picked up message: " + message);
}
}
What changes would I need to make in order achieve the desired behavior?
App1 application.properties file:
spring.activemq.in-memory=false
spring.activemq.pool.enabled=false
server.port=9000
activemq.broker-url=tcp://localhost:61616
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
security.basic.enabled=false
management.security.enabled=false
App1 JmsConfig class
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
#Configuration
public class JmsConfig {
#Value("${activemq.broker-url}")
private String brokerUrl;
#Bean
public Queue queue() {
return new ActiveMQQueue("testqueue");
}
#Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
factory.setBrokerURL(brokerUrl);
return factory;
}
#Bean
public JmsTemplate jmsTemplate() {
return new JmsTemplate(activeMQConnectionFactory());
}
}
App1 Producer class
import javax.jms.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/rest/publish")
public class ProducerResource {
#Autowired
JmsTemplate jmsTemplate;
#Autowired
Queue queue;
#GetMapping("/{message}")
public String publishMessage(#PathVariable("message") final String message) {
jmsTemplate.convertAndSend(queue, message);
return "Published successfully";
}
}
App1 consumer class is the same class I used in the consumer only application (listed above).
For your consumer app, you do need to add Pool connection factory & JMS message listener factory for your consumer JMStemplate to start receiving messages.
#Configuration
#EnableJms
public class ConsumerConfig {
#Value("${activemqbrokerurl}")
private String brokerUrl;
#Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
activeMQConnectionFactory.setBrokerURL(brokerUrl);
return activeMQConnectionFactory;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(activeMQConnectionFactory());
factory.setConcurrency("{#setDesiredConcurrency}");
return factory;
}
}
Spring's MessagListenerContainer should be used for message consumption. This provides all the power of MDBs - efficient JMS consumption and pooling of the message listeners - but without requiring a full EJB container.You can use the activemq-pool org.apache.activemq.pool.PooledConnectionFactory for efficient pooling of the connections and sessions for your collection of consumers, or you can use the Spring JMS org.springframework.jms.connection.CachingConnectionFactory to achieve the same effect.
You can read more about it here
To me, this appears to be just about the simplest possible spring integration example. I'm trying to learn from the si4demo. But when I run it, I get this exception:
Exception in thread "main"
org.springframework.messaging.MessageDeliveryException: Dispatcher has
no subscribers for channel 'application.inbox'.; nested exception is
org.springframework.integration.MessageDispatchingException:
Dispatcher has no subscribers
Where am I going wrong? Doesn't the defined flow create a subscription to the inbox channel?
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.messaging.MessageChannel;
#Configuration
#ComponentScan
#IntegrationComponentScan
public class App {
public static void main(String[] args) {
try (ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args)) {
final Gateway gateway = ctx.getBean(Gateway.class);
final String rs = gateway.send("hullo");
System.out.println(rs);
}
}
private static final String INBOX = "inbox";
#MessagingGateway(defaultRequestChannel = INBOX)
public interface Gateway {
String send(String msg);
}
#Bean
public IntegrationFlow flow() {
return IntegrationFlows.from(INBOX)
.transform(p -> "world")
.get();
}
#Bean(name = INBOX)
public MessageChannel inbox() {
return new DirectChannel();
}
}
Looks like you have missed the main player - #EnableIntegraion:
Starting with version 4.0, the #EnableIntegration annotation has been introduced, to allow the registration of Spring Integration infrastructure beans (see JavaDocs). This annotation is required when only Java & Annotation configuration is used, e.g. with Spring Boot and/or Spring Integration Messaging Annotation support and Spring Integration Java DSL with no XML integration configuration.
http://docs.spring.io/spring-integration/docs/4.3.0.BUILD-SNAPSHOT/reference/html/overview.html#configuration-enable-integration