Camel, Netty, MINA: Two Way Asynchronous Communications Between Server and Client - spring

From my limited understanding of Camel's MINA2 and Netty Components I see that I can do one way communications and request-reply communications but I want to be able to send messages from the client to the server and from the server to the client asynchronously.
For example, I would like to write a simple server to echo back to any connected clients what was submitted. In addition, for any connected client I want to send the current time every thirty seconds. Is there a good way to do this? Below is a sample of what I have but don't know how to setup the part that allows the server to send messages to the connected client.
The netcat portion of the code snippets below work, and printing the current time to the server's console (via logging) works, but want to send it back to the connected client. I should note that the client is legacy software and I don't have the ability to change it. Only the server portions.
TL;DR: I want the server to send asynchronous messages to connected legacy clients that I have to support as is. Is there a built in way to do this in Camel without writing custom code? Or if not, what I would have to write?
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="echo" class="netcat.Echo" />
<camel:errorHandler id="camelErrorHandler" type="DefaultErrorHandler" />
<camelContext id="camelContext" errorHandlerRef="camelErrorHandler" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://sendTime?cron=0/5+*+*+*+*+?" />
<to uri="bean:netcat.CurrentTime?method=getCurrentTime()" />
</route>
<route>
<from uri="netty:tcp://localhost:5555?textline=true" />
<to uri="bean:echo" />
</route>
</camelContext>
</beans>
log4j.properties
log4j.rootLogger=INFO, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %d [%t] %-5p %c %x - %m%n
CurrentTime.java
package netcat;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CurrentTime {
private static final Logger LOG = LoggerFactory.getLogger(CurrentTime.class);
private CurrentTime() {
}
public static String getCurrentTime() {
String currentTime = DateTime.now().toString();
LOG.info("Current Time is {}.", currentTime);
return currentTime;
}
}
Echo.java
package netcat;
import org.apache.commons.lang3.StringUtils;
public class Echo {
public String echo(String message) {
return StringUtils.join(new Object[] { "Echoing: ", message });
}
}

Related

High Efficient MDB using spring jms or ntegration

I have requirement where I need receive message from MQ every seconds , the message will be in XML format , so i need to write a high effecient MDB. Problem here is I am new to MQ,JMS,Spring JMS and Spring Integration but not spring tough.
Based on google search so far I am able to write below code
MDB
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class MyMessageListener implements MessageListener{
#Override
public void onMessage(Message m) {
TextMessage message=(TextMessage)m;
try{
System.out.println(message.getText());
}catch (Exception e) {e.printStackTrace(); }
}
}
XMl config
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
<bean id="listener" class="com.springexample.MyMessageListener"></bean>
<jms:listener-container container-type="default" connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="myfirstqueue" ref="listener" method="onMessage"></jms:listener>
</jms:listener-container>
</beans>
I know what i have written is very basic one but i dont know what is the efficient one , how to provide transaction support and how to handle such load where i am going to recieve message every seconds.
Should i use Spring JMS or Spring Integration any help is much appreciated.
The question you asked is which to use: definitely go Spring JMS

Persist message in ActiveMQ across server restart

I am learning Spring Integration JMS. Since ActiveMQ is a message broker. I referring to project given here-> http://www.javaworld.com/article/2142107/spring-framework/open-source-java-projects-spring-integration.html?page=2#
But I want to know how can I persist message in ActiveMQ. I mean I started ActiveMQ then send request using REST client. I am calling publishService.send( message ); in for loop for 50 times and and the receiver end I have sleep timer of 10 seconds. So that 50 messages gets queued and its start processing at 10 seconds interval.
EDIT:
Look at the screen shot below:
It says 50 messages enqueued and 5 of them have been dequeued.
But then in between I stopped ActiveMQ server and by the time it has consumed 5 messages out of 50 and then again restart it.
But then I was expecting it to show remaining 45 in Messages Enqueued column. But I can see 0(see screenshot below) there and they all vanished after server restart without having to persist remaining 45 messages. How can I come over this problem ?
Please have a look at the configuration below:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:int-jme="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<!-- Component scan to find all Spring components -->
<context:component-scan base-package="com.geekcap.springintegrationexample" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="order" value="1" />
<property name="messageConverters">
<list>
<!-- Default converters -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
<!-- Define a channel to communicate out to a JMS Destination -->
<int:channel id="topicChannel"/>
<!-- Define the ActiveMQ connection factory -->
<bean id="connectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<!--
Define an adaptor that route topicChannel messages to the myTopic topic; the outbound-channel-adapter
automagically fines the configured connectionFactory bean (by naming convention
-->
<int-jms:outbound-channel-adapter channel="topicChannel"
destination-name="topic.myTopic"
pub-sub-domain="true" />
<!-- Create a channel for a listener that will consume messages-->
<int:channel id="listenerChannel" />
<int-jms:message-driven-channel-adapter id="messageDrivenAdapter"
channel="getPayloadChannel"
destination-name="topic.myTopic"
pub-sub-domain="true" />
<int:service-activator input-channel="listenerChannel" ref="messageListenerImpl" method="processMessage" />
<int:channel id="getPayloadChannel" />
<int:service-activator input-channel="getPayloadChannel" output-channel="listenerChannel" ref="retrievePayloadServiceImpl" method="getPayload" />
</beans>
Also please see the code:
Controller from where I am sending message in for loop at once:
#Controller
public class MessageController
{
#Autowired
private PublishService publishService;
#RequestMapping( value = "/message", method = RequestMethod.POST )
#ResponseBody
public void postMessage( #RequestBody com.geekcap.springintegrationexample.model.Message message, HttpServletResponse response )
{
for(int i = 0; i < 50; i++){
// Publish the message
publishService.send( message );
// Set the status to 201 because we created a new message
response.setStatus( HttpStatus.CREATED.value() );
}
}
}
Consumer code to which I have applied timer:
#Service
public class MessageListenerImpl
{
private static final Logger logger = Logger.getLogger( MessageListenerImpl.class );
public void processMessage( String message )
{
try {
Thread.sleep(10000);
logger.info( "Received message: " + message );
System.out.println( "MessageListener::::::Received message: " + message );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Further by searching more I found here that As per the JMS specification, the default delivery mode is persistent. But in my case it does not seems to be worked.
Please help me to have right configuration in place so that messages can be persist across broker failure.
This is typically not a problem, but the way activeMQ was built.
you can find the following explanation in book 'ActiveMQ in action'
Once a message has been consumed and acknowledged by a message
consumer, it’s typically deleted from the broker’s message store.
So when you restart your server, it only shows you the messages which are in broker's message store. In most cases you will never have the need to have a look at the processed messages.
Hope this helps!
Good luck!

How to integration test some Spring JMS config

I wonder if anyone can help. My starter for 10 is that I know very little (next to nothing) about JMS and messaging in general - so please go easy with me with any answers/comments :)
Given that this is a learning exerise for me, I'm trying to put together a very basic Spring JMS config, and then write some integration tests to help me understand how it all works.
This is my current Spring context config with its JMS components:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:amq="http://activemq.apache.org/schema/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<bean class="com.lv.gi.jmstest.ApplicationContextProvider" />
<!-- Embedded ActiveMQ Broker -->
<amq:broker id="broker" useJmx="false" persistent="false">
<amq:transportConnectors>
<amq:transportConnector uri="tcp://localhost:0" />
</amq:transportConnectors>
</amq:broker>
<!-- ActiveMQ Destination -->
<amq:queue id="destination" physicalName="myQueueName" />
<!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->
<amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
<!-- JMS Producer Configuration -->
<bean id="jmsProducerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="jmsProducerConnectionFactory"
p:defaultDestination-ref="destination" />
<bean class="com.lv.gi.jmstest.JmsMessageProducer">
<constructor-arg index="0" ref="jmsProducerTemplate" />
</bean>
<!-- JMS Consumer Configuration -->
<bean id="jmsConsumerConnectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory"
depends-on="broker"
p:targetConnectionFactory-ref="jmsFactory" />
<jms:listener-container container-type="default"
connection-factory="jmsConsumerConnectionFactory"
acknowledge="auto">
<jms:listener destination="myQueueName" ref="jmsMessageListener" />
</jms:listener-container>
<bean id="jmsMessageListener" class="com.lv.gi.jmstest.JmsMessageListener" />
</beans>
My JmsMessageProducer class has a postMessage method as follows:
public void postMessage(final String message) {
template.send(new MessageCreator() {
#Override
public Message createMessage(final Session session) throws JMSException {
final TextMessage textMessage = session.createTextMessage(message);
LOGGER.info("Sending message: " + message);
return textMessage;
}
});
}
And my JmsMessageListener (implements MessageListener) has an onMessage method as follows:
public void onMessage(final Message message) {
try {
if (message instanceof TextMessage) {
final TextMessage tm = (TextMessage)message;
final String msg = tm.getText();
LOGGER.info("Received message '{}'", msg);
}
} catch (final JMSException e) {
LOGGER.error(e.getMessage(), e);
}
}
In my test class, I can fire up the Spring context, get the JmsMessageProducer bean, and call postMessage; and I see the message on the console as expected:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/com/lv/gi/jmstest/JmsMessageListenerTest-context.xml" })
public class TestJms {
private JmsMessageProducer jmsMessageProducer;
#Before
public void setup() {
jmsMessageProducer = ApplicationContextProvider.getApplicationContext().getBean(JmsMessageProducer.class);
}
#Test
public void doStuff() throws InterruptedException {
jmsMessageProducer.postMessage("message 1");
}
}
Whilst this works, its not really much of a test, because other than me visually seeing the message received on the console, I can't assert the message has been received.
We use mockito, so I'm wondering if there is a way within my test that I can replace the MessageListener bean with a mock, then call verify on it. I guess I could do it by providing a different Spring context file for the purpose of these tests, but that might not work well with my next requirement ...
My end goal with all of this is to create a Topic, where my message producer can fire a message onto the queue, and 1 of more MessageListeners will read the message off the queue, and when all registered listeners have read the message, the message is deleted from the queue. (I think Topic is the right terminology for this!)
To prove that this system would work, I would want a test where I can fire up the Spring context. The first thing I'd want to do is replace the listener with 3 mocks all wired to the same destination so that I can use verify on each of them. I'd post a message, then verify that each mock has received. Then I'd want to remove/disable 2 of the listeners, call postMessage, and verify the onMessage method was called on the one remaining mock listener. Then perhaps wait a while, and re-establish the 2 mocks, and verify their onMessage method was called. And finally, check the message is no longer on the queue (by virtue of the fact that the 3 registered listeners had all received the message)
With the above in mind, I think what I'm trying to do is register and de-register (or disable) listeners against the destination at runtime, and if I can do that, then I can register mocks.
Phew!, that's complicated!, but I hope it makes sense as to what I'm trying to do?
Any pointers as to how to achieve this? Many thanks in advance,
Nathan
In my opinion, as soon as you are doing integration testing, you should not try to mock anything.
On one hand you write unit tests. For example, you could test the behaviours of your consumer, by calling the onMessage method of jmsMessageListener directly from your tests. You typically don't use SpringJUnit4ClassRunner for this kind of test, and you typically use Mockito to mock the dependencies of the object you are testing.
On the other hand you have integration tests. These are testing the behaviour of your entire application. It would make sense to use SpringJUnit4ClassRunner.class here, but not Mockito. You should test that whatever your jmsListener was supposed to do has been done. For example, if your application was supposed to write logs about the incoming message, open the log file and check it.
Your example here is very simple, maybe this is why you are confused (in my opinion). With a more complex listener, it would be more natural to it isolated from the rest of the system.

Spring not detecting #Scheduled Methods

I am running Spring 3.2.3.RELEASE and I have several methods within #Service decorated classes that are Scheduled tasks and thus decorated with the #Scheduled annotation.
All the Spring beans are detected and instantiated within the container, however the #Scheduled annotations are never invoked.
I have several application contexts, but the main file is described below as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<import resource="classpath:core-properties.xml" />
<import resource="classpath:core-datasource.xml" />
<import resource="classpath:core-task-scheduler.xml" />
<context:component-scan base-package="com.atlaschase.project.core">
<context:exclude-filter type="regex"
expression="com.atlaschase.project.core.services.jms.*" />
<context:exclude-filter type="regex"
expression="com.atlaschase.project.core.services.processor.*" />
<context:exclude-filter type="regex"
expression="com.atlaschase.project.core.services.remote.*" />
<context:exclude-filter type="regex"
expression="com.atlaschase.project.core.bootstrap.populators.*" />
</context:component-scan>
<bean id="bufferPopulator" class="com.atlaschase.project.core.services.jms.buffer.BufferPopulator"/>
<bean id="eventBuffer" class="com.atlaschase.project.core.services.jms.buffer.EventBuffer"/>
<bean id="processorEventHandler" class="com.atlaschase.project.core.services.jms.buffer.ProcessorEventHandler"/>
The other important file is imported as "core-task-scheduler.xml". This is configured as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="1"/>
<task:scheduler id="myScheduler" pool-size="5"/>
</beans>
Originally, the executor reference (above) was defined in the main application context, but I split this out as an import after reading that other similar problems had been solved in this way. Unfortunately this has not helped. I have also moved the import declarations around, but this seems to have no effect.
Declaring Scheduled methods in the Spring Application Context directly works fine - however I am very keen to use annotations.
Here is the annotated class:
**
* Service that batches the saving of position updates into a periodically executed
* process.
*/
#Service
public class PositionAggregatorService {
static Logger logger = Logger.getLogger(AircraftPositionAggregatorService.class);
// The service will not execute within 1 minute of a previous batch attempt.
// This paramater is updated by a message from another node indicating that
// they are commencing a batch save of position updates.
private DateTime blockingTime;
private Map<Long, List<Position>> positions;
#Autowired
private PositionDao positionDao;
#Autowired
private InternalPublisher internalEventPublisher;
#PostConstruct
private void initialise(){
positions = new ConcurrentHashMap<Long, List<Position>>();
}
/*
* Scheduled to execute every 10 minutes as long current time is not
* before the blocking time threshold.
*
* */
#Scheduled(fixedRate=6000)
public void batchSavePositionUpdates(){
if(blockingTime != null){
if(DateTime.now(DateTimeZone.UTC).isBefore(blockingTime)){
return;
}
}
PositionPersistStartedNotification started = new PositionPersistStartedNotification(DateTime.now(DateTimeZone.UTC), DateTime.now(DateTimeZone.UTC).plusMinutes(2));
internalEventPublisher.publishPositionPersistStartedNotification(started);
DateTime mostRecentUpdateTime = null;
List<Position> positionsToSave = new ArrayList<Position>();
for(Long flightId : positions.keySet()){
List<Position> positionList = positions.get(flightId);
for(Position position : positionList){
if(mostRecentUpdateTime == null){
mostRecentUpdateTime = new DateTime(position.getTime());
}
else{
DateTime positionTime = new DateTime(position.getTime());
if(positionTime.isAfter(mostRecentUpdateTime)){
mostRecentUpdateTime = positionTime;
}
}
positionsToSave.add(position);
}
}
Boolean successfulSave = false;
try{
positionDao.save(positionsToSave);
successfulSave = true;
logger.info(positionsToSave.size() + " Position Updates saved successfully");
}catch(Exception exception){
logger.error("Failed to persist latest position updates to database");
logger.error(exception);
}
if(successfulSave){
removeSavedPositions(mostRecentUpdateTime);
PositionPersistEndedNotification ended = new PositionPersistEndedNotification(DateTime.now(DateTimeZone.UTC), mostRecentUpdateTime);
internalEventPublisher.publishPositionPersistEndedNotification(ended);
}
}
}
Any help would be appreciated.
Is the Spring context loaded successfully in runtime? I see you have some inconsistencies in namespace definitions where various versions co-exist in the xsd (3.0 and 3.2). Can you try having consistently the same version in these namespaces and try again?
The application was being started by listening for the context to be loaded and then executing a method upon the ContextRefreshedEvent.
When I removed this ApplicationEventListener from the application and simply invoked a public method on the bean to start the service (instead of relying in the ApplicationEventListener) - the application then started normally with all #Scheduled annotations working as expected.

Use of Spring Framework for RabbitMQ is reducing the performance

I have created a producer, which was using com.rabbitmq.client.connectionFactory and was sending 1,000,000 messages (40 Bytes) in 100 seconds.
But now I want an spring abstraction. I was unable to use com.rabbitmq.client.connectionFactory rather I had to use org.springframework.amqp.rabbit.connection.SingleConnectionFactory. Using this connection factory only 100,000 messages (40 Bytes) are send to the broker in 100 seconds.
Does anybody have experience why the performance is reduced so much (around 90%).
The code using "import com.rabbitmq.client.ConnectionFactory;" is ->
package Multiple_queues_multiple_consumers;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
private static Connection myConnection;
private static Channel myChannel;
public static String myQueueName;
public static void main(String[] args) throws IOException {
long startTime=0;
int count=0;
ConnectionFactory myFactory=new ConnectionFactory();
myFactory.setHost("localhost");
try {
myConnection = myFactory.newConnection();
myChannel = myConnection.createChannel();
String myExchange = "wxyzabc";
String myBody = "This is a message : message numberxxxxxx";
String myRoutingKey = "RoutingKey";
myQueueName = "new_Queue";
myChannel.exchangeDeclare(myExchange, "direct", true, false, null);
myChannel.queueDeclare(myQueueName, true, false, false, null);
myChannel.queueBind(myQueueName, myExchange, myRoutingKey);
startTime=System.currentTimeMillis();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setDeliveryMode(2);
startTime=System.currentTimeMillis();
while(count++<=10000){
myChannel.basicPublish(myExchange, myRoutingKey, true, true, properties, myBody.getBytes() );
}
System.out.println(System.currentTimeMillis()-startTime);
} catch (Exception e){
System.exit(0);
}
}
}
The code using SpringFramework is :->
Producer1.java
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Producer1 {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Producer1.xml");
AmqpAdmin amqpAdmin = context.getBean(RabbitAdmin.class);
Queue queue = new Queue("sampleQueue");
DirectExchange exchange = new DirectExchange("myExchange");
Binding binding = new Binding(queue, exchange, "");
amqpAdmin.declareQueue(queue);
amqpAdmin.declareExchange(exchange);
amqpAdmin.declareBinding(binding);
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
String routingKey = "";
String myBody = "This is a message : message numberxxxxxx";
Message Msg = new Message(myBody.getBytes(), null);
int count=0;
long CurrTime = System.currentTimeMillis();
while(count++<=10000){
rabbitTemplate.send(routingKey, Msg);
//System.out.println("Message Sent");
}
System.out.println(System.currentTimeMillis()-CurrTime);
}
}
Producer1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Define a connectionFactory -->
<bean id="rabbitConnectionFactory" class="com.rabbitmq.client.ConnectionFactory">
<property name="host" value="localhost" />
</bean>
<bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.SingleConnectionFactory">
<constructor-arg ref="rabbitConnectionFactory"/>
</bean>
<!-- Tell the Admin bean about that connectionFactory and initialize it, create a queue and an exchange on Rabbit Broker using the RabbitTemplate provided by Spring framework-Rabbit APIs -->
<bean id="Admin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="connectionFactory" />
</bean>
<bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate"
p:connectionFactory-ref="connectionFactory"
p:routingKey="myRoutingKey"
p:exchange="myExchange" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Define a connectionFactory -->
<bean id="connectionFactory" class="com.rabbitmq.client.connectionFactory">
<constructor-arg value="localhost" />
<property name="username" value="guest" />
<property name="password" value="guest" />
</bean>
<bean id="Admin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="connectionFactory" />
</bean>
</beans>
Using this xml file, the error appears saying org.springframework.amqp.rabbit.core.RabbitAdmin could not cast com.rabbitmq.client.connectionFactory for connectionfactory bean.
The exact error is: "nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.rabbitmq.client.ConnectionFactory] to required type [org.springframework.amqp.rabbit.core.RabbitTemplate]: no matching editors or conversion strategy found" .
Hence i have to use bean:
<bean id="connectionFactory"
class="org.springframework.amqp.rabbit.connection.SingleConnectionFactory">
</bean>
Are you sure that you used the same Rabbit MQ broker? Could you be using a broker on a different server, or an upgraded/downgraded version of RabbitMQ?
The other thing to look at is your jvm. Is it possible that you don't have enough memory configured and now the garbage collector is thrashing? Run top and see if the jvm's memory usage is close to the configured memory size.
Are you using an old version of RabbitMQ. Lots of Linux distros include RabbitMQ 1.7.2 which is an old version that has problems with large numbers of messages. Large is hard to define because it depends on your RAM, but RabbitMQ does not like to use more than 40% of RAM because it needs to copy a persistence transaction log in order to process it and clean it for log rollover. This can cause RabbitMQ to crash, and, of course, processing the huge logs will slow it down. RabbitMQ 2.4.1 handles the persister logs much better, in smaller chunks, and it also has much, much faster message routing code.
This still sounds to me like a Java problem, either Spring is just a pig and is terribly inefficient, or you have not given your jvm enough RAM to avoid frequent gc runs. What setting are you using for -Xmx?

Resources