We have a requirement for the FTP client to download a file whose name and directory is provided at run-time. So, the FTP client may be asked to download file1.txt from foo1/foo2 directory path on the remote server.
We do have a solution using Spring Integration FTP outbound gateway. With this solution to make it dynamic:
the ApplicationContext for the gateway is created
the gateway properties get set using file name and remote directory path
the file is downloaded
the ApplicationContext is closed.
What we're not happy about is that the ApplicationContext is created and closed every time which obviously affects performance. Is there a way to dynamically pass the file name and the directory path to the gateway without reloading the Appplication Context every time?
Your help will be greatly appreciated.
Here's the main code and configuration:
package com.cvc.ipcdservice.ftp;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.StandardEnvironment;
public class DynamicFtpClient {
private static final Logger LOGGER = LoggerFactory
.getLogger(DynamicFtpClient.class);
public void download(final FtpMetaData ftpMetaData) {
final ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "/META-INF/spring/integration/FtpOutboundGateway-context.xml" },
false);
setEnvironment(ctx, ftpMetaData);
ctx.refresh();
final ToFtpFlowGateway toFtpFlow = ctx.getBean(ToFtpFlowGateway.class);
// execute the flow (mget to download from FTP server)
final List<Boolean> downloadResults = toFtpFlow.mGetFiles("/");
LOGGER.info(
"Completed downloading from remote FTP server. ftpMetaData:{}, downloadResults.size:{} ",
ftpMetaData, downloadResults.size());
ctx.close();
}
/**
* Populate {#code ConfigurableApplicationContext} with Provider-specific
* FTP properties.
*
* #param ctx
* #param customer
*/
private void setEnvironment(final ConfigurableApplicationContext ctx,
final FtpMetaData ftpMetaData) {
final StandardEnvironment env = new StandardEnvironment();
final Properties props = new Properties();
// populate properties for customer
props.setProperty("ftp.host", ftpMetaData.getHost());
props.setProperty("ftp.port", ftpMetaData.getPort());
props.setProperty("ftp.userid", ftpMetaData.getUserName());
props.setProperty("ftp.password", ftpMetaData.getPassword());
// props.setProperty("remote.directory", "/");
// WARNING: the file name pattern has to be surrounded by single-quotes
props.setProperty("ftp.remote.filename.pattern",
"'" + ftpMetaData.getFileNamePattern() + "'");
props.setProperty("ftp.local.dir", ftpMetaData.getLocalDirectory());
final PropertiesPropertySource pps = new PropertiesPropertySource(
"ftpprops", props);
env.getPropertySources().addLast(pps);
ctx.setEnvironment(env);
}
}
<?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-ftp="http://www.springframework.org/schema/integration/ftp"
xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
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">
<context:property-placeholder/>
<int:gateway id="gw" service-interface="com.cvc.ipcdservice.ftp.ToFtpFlowGateway"
default-request-channel="inbound"/>
<bean id="ftpSessionFactory"
class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${ftp.host}"/>
<property name="port" value="${ftp.port}"/>
<property name="username" value="${ftp.userid}"/>
<property name="password" value="${ftp.password}"/>
</bean>
<int-ftp:outbound-gateway id="gatewayGET"
local-directory="${ftp.local.dir}"
session-factory="ftpSessionFactory"
request-channel="inbound"
command="mget"
command-options="-P"
expression="${ftp.remote.filename.pattern}"/>
</beans>
There is no need to create the context for each request.
Instead of using a literal for the expression:
props.setProperty("ftp.remote.filename.pattern",
"'" + ftpMetaData.getFileNamePattern() + "'");
Use an expression based on the request; e.g.
props.setProperty("ftp.remote.filename.pattern",
"payload");
Then simply send the required path in your gateway call...
final List<Boolean> downloadResults = toFtpFlow.mGetFiles("/some/path/*.txt");
Related
I am new to drools and I have got a problem while I am trying to integrate drools with spring following the guide of the drools doc page.Here's the link :http://docs.jboss.org/drools/release/6.3.0.Final/drools-docs/html_single/index.html#d0e13904.
I write some code and a junit test case.Everything seems go well,the case runs correctly and no exception was thrown.But the rules are not fired.I am sure that the rule file is ok.
Here is the rule file:
package com.huateng.risk;
import com.huateng.risk.fact.ConsumeFact;
global com.huateng.risk.service.NoticeService noticeService;
rule "day consume times limit"
//day consume times limit 5
when
$info : ConsumeFact (dayTimes >= 5 , checked == true);
then
//noticeService.notice("day consume times limit over");
System.out.println("day consume times limit over");
$info.setChecked(false);
update($info);
end
rule "day consume amount limit"
//3000
when
$info : ConsumeFact (dayAmt >= 3000 , checked == true );
then
//noticeService.notice("day consume amt limit over");
System.out.println("day consume amt limit over");
$info.setChecked(false);
update($info);
end
rule "month consume times limit"
//day consume times limit 15
when
$info : ConsumeFact (monthTimes >= 15 , checked == true );
then
//noticeService.notice("month consume times limit over");
System.out.println("month consume times limit over");
$info.setChecked(false);
update($info);
end
rule "month consume amount limit"
//3000
when
$info : ConsumeFact (monthAmt >= 8000 , checked == true );
then
//noticeService.notice("month consume amt limit over");
System.out.println("month consume amt limit over");
$info.setChecked(false);
update($info);
end
rule "consume amount limit"
//2000
when
$info : ConsumeFact (amt >= 2000 , checked == true );
then
//noticeService.notice("consume amt limit over");
System.out.println("consume amt limit over");
$info.setChecked(false);
update($info);
end
I have tested this drl file with the code :
package com.huateng.risk.demo;
import org.kie.api.KieServices;
import org.kie.api.event.rule.DebugAgendaEventListener;
import org.kie.api.event.rule.DebugRuleRuntimeEventListener;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import com.huateng.risk.fact.ConsumeFact;
import com.huateng.risk.service.NoticeServiceImpl;
/**
* This is a sample file to launch a rule package from a rule source file.
*/
public class RiskHandleMain {
public static final void main(final String[] args) {
// KieServices is the factory for all KIE services
KieServices ks = KieServices.Factory.get();
// From the kie services, a container is created from the classpath
KieContainer kc = ks.getKieClasspathContainer();
execute( kc );
}
public static void execute( KieContainer kc ) {
// From the container, a session is created based on
// its definition and configuration in the META-INF/kmodule.xml file
KieSession ksession = kc.newKieSession("RiskHandleKS");
// Once the session is created, the application can interact with it
// In this case it is setting a global as defined in the
// org/drools/examples/helloworld/HelloWorld.drl file
ksession.setGlobal( "noticeService", new NoticeServiceImpl() );
// The application can also setup listeners
ksession.addEventListener( new DebugAgendaEventListener() );
ksession.addEventListener( new DebugRuleRuntimeEventListener() );
// To setup a file based audit logger, uncomment the next line
// KieRuntimeLogger logger = ks.getLoggers().newFileLogger( ksession, "./helloworld" );
// To setup a ThreadedFileLogger, so that the audit view reflects events whilst debugging,
// uncomment the next line
// KieRuntimeLogger logger = ks.getLoggers().newThreadedFileLogger( ksession, "./helloworld", 1000 );
// The application can insert facts into the session
final ConsumeFact info = new ConsumeFact();
info.setAmt(2000L);
info.setDayTimes(8L);
info.setDayAmt(2000L);
info.setMonthTimes(8L);
info.setMonthAmt(5000L);
ksession.insert( info );
// and fire the rules
ksession.fireAllRules();
// Remove comment if using logging
// logger.close();
// and then dispose the session
ksession.dispose();
}
}
In my spring integration case, i have two spring bean files:
The first:
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- proxy-target-class -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<context:component-scan base-package="com.huateng.risk,org.kie.spring" />
<import resource="classpath:spring-drools.xml" />
</beans>
And the second:
<?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:kie="http://drools.org/schema/kie-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd ">
<kie:kmodule id="riskKmodule">
<kie:kbase name="riskKbase" packages="com.huateng.risk">
<kie:ksession name="ksRiskHandle">
<!-- <kie:fileLogger file="drools" threaded="true"
interval="10" /> -->
<!-- <kie:batch>
<kie:set-global identifier="noticeSerivce">
<bean class="com.huateng.risk.service.NoticeServiceImpl"/>
</kie:set-global>
</kie:batch> -->
<!-- <kie:listeners>
<kie:ruleRuntimeEventListener
ref="org.kie.api.event.rule.DebugRuleRuntimeEventListener" />
<kie:agendaEventListener
ref="org.kie.api.event.rule.DebugAgendaEventListener" />
<kie:processEventListener
ref="org.drools.core.event.DebugProcessEventListener" />
</kie:listeners> -->
</kie:ksession>
</kie:kbase>
</kie:kmodule>
</beans>
In the second file, the kbase configurs the resources package which exactly stores the drl files.
I have got two questions:
1 As I wrote before, my test case runs normally with no exceptions,but the rules are not fired.And when i debug my code,i find the something wrong.
Here is my code:
package com.huateng.risk;
import java.util.Collection;
import java.util.List;
import org.kie.api.KieBase;
import org.kie.api.cdi.KBase;
import org.kie.api.cdi.KSession;
import org.kie.api.definition.KiePackage;
import org.kie.api.definition.rule.Rule;
import org.kie.api.event.rule.AgendaEventListener;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.huateng.risk.fact.ConsumeFact;
import com.huateng.risk.service.NoticeService;
#Component("riskHandle")
public class RiskHandle {
#Autowired
private NoticeService noticeService;
#KSession("ksRiskHandle")
private KieSession ksession;
public void execute(ConsumeFact info ) {
try{
ksession.insert( info );
Environment env = ksession.getEnvironment();
KieBase kbase = ksession.getKieBase();
Collection<KiePackage> packages = kbase.getKiePackages();
KiePackage pkg = kbase.getKiePackage("com.huateng.risk");
Rule rule = kbase.getRule("com.huateng.risk", "day consume times limit");
ksession.fireAllRules();
ksession.dispose();
}catch(Exception e){
e.printStackTrace();
}
}
public void setNoticeService(NoticeService noticeService) {
this.noticeService = noticeService;
}
public void setKsession(KieSession ksession) {
this.ksession = ksession;
}
}
When I was debugging my code, i found the "packages" was empty array.So was the "pkg" and the "rule".It seems that the kbase did not loaded the resources stored in the sub-folder "/com/huateng/risk" under the "src/main/resources" which is defined as a source folder by maven default.
So Have i done wrong somewhere with spring integration?
2 I am trying to set globals to do some bussiness stuff.Let's back forward to the second spring bean file.When i uncommented the set-globals config ,i got an exception : Unexpected globals.
How to configure the globals with spring integration ?
Here is the set-globals config in the second spring bean file:
<kie:batch>
<kie:set-global identifier="noticeSerivce">
<bean class="com.huateng.risk.service.NoticeServiceImpl"/>
</kie:set-global>
</kie:batch>
I found something not clear about the autowire=byType behavior.
Java code under package my:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class UserService {
#Autowired
private User user1;
#Autowired
private User user2;
public String getNames() {
return user1.getName() + " & " + user2.getName();
}
}
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:component-scan base-package="my"/>
<context:annotation-config/>
<bean id="user1" class="my.User" autowire="byType">
<constructor-arg value="Freewind"/>
</bean>
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
</beans>
Running code:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean(UserService.class);
System.out.println(service.getNames());
}
}
It's working well and prints:
Freewind & Lily
But I was expecting it should not work, because I used autowire="byType" when I defined the beans, and there are two beans with the same type User in UserService.
And, if I changed the name of the bean, say, user1 -> user999, it will report some error like No qualifying bean of type [my.User] is defined error.
It seems spring will automatic check the name even if I specified byType, which is strange.
PS: I've tested with spring 4.1.3.RELEASE and 3.2.2.RELEASE, same behavior.
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
The autowire="byType" here means that you want to have (missing) dependencies injected into this bean byType. It only applies to the bean the attribute is placed on. In the xml namespace the default for all the beans could be set.
However in your case you are using actually using annotations (note <context:annotation-config /> is already implied by the usage of </context:component-scan />). Annotation driven injection (#Autowired, #Inject are always by type, #Resource uses a name or jndi lookup and as fallback by name).
When starting the application and scanning for components for each needed dependency the DependencyDescriptor is created. This class contains the details used for autowiring, it amongst other things contains the type and the name. The name, in case of a Field is derived from the actual name.
i am trying to set the value from the springapp-servlet.xml and it fails to set the property by giving error message
Failed to convert property value of type [java.lang.String] to required type [ProductManager] for property 'productManager'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [ProductManager] for property 'productManager': no matching editors or conversion strategy found
my code
springapp-servlet.xml
view plaincopy to clipboardprint?
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="productManager" class="SimpleProductManager">
<property name="products">
<list>
<ref bean="product1"/>
<ref bean="product2"/>
</list>
</property>
</bean>
<bean id="product1" class="Product">
<property name="description" value="Chair"/>
</bean>
<bean id="product2" class="Product">
<property name="description" value="Desk"/>
</bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>
<bean name="/hello.htm" class="HelloController">
<property name="productManager" value="productManager"/>
</bean>
<!-- we can prefix="/"
http://localhost:8080/HelloSpring/hello.htm
specify the path in modelview from the controller
OR
Decouple the view from the controller
prefix="/WEB-INF/jsp/"
-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
</beans>
HelloController
view plaincopy to clipboardprint?
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author gopc
*/
import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
public class HelloController implements Controller {
private ProductManager productManager;
protected final Log logger = LogFactory.getLog(getClass());
//Writing some business logic in the controller
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String now = (new java.util.Date()).toString();
logger.info("returning hello view with " + now);
Map<String, Object> myModel = new HashMap<String, Object>();
myModel.put("now", now);
myModel.put("products", this.productManager.getProducts());
return new ModelAndView("hello", "model", myModel);
}
public void setProductManager(ProductManager productManager)
{
this.productManager = productManager;
}
}
SimpleProductManager
view plaincopy to clipboardprint?
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author gopc
*/
import java.util.List;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
public class SimpleProductManager implements ProductManager{
private List<Product> products;
protected final Log logger = LogFactory.getLog(getClass());
public List<Product> getProducts()
{
logger.info("inside getProducts ");
return products;
}
public void increasePrice (int per)
{
if (products != null)
{
for (Product prod : products)
{
double newPrice = prod.getPrice() * (100 + per) /100;
prod.setPrice(newPrice);
}
}
}
public void setProducts(List <Product> products )
{
logger.info("inside setProducts ");
this.products = products;
}
}
Change
<property name="productManager" value="productManager"/>
<!-- sets "productManager" to "productManager" String -->
to :
<property name="productManager" ref="productManager"/>
<!-- sets "productManager" to bean with id="productManager" -->
Right now you're setting the productManager property of HelloController to a "productManager" String, and what you (probably) want is to wire it up with productManager bean defined earlier in the context.
I have destroy method in my bean but it is not showing in the out put. Could you please help me here.
package com.vaannila;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloWorldApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Ticket helloWorld = (Ticket) context.getBean("ticket");
helloWorld.setTicketNo("ABC009");
helloWorld.display();
context.close();
}
}
below is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloWorld" class="com.vaannila.HelloWorld">
<property name="message" value="Hello World!"></property>
</bean>
<bean id="ticket" class="com.vaannila.Ticket"
scope="prototype" init-method="init" destroy-method="destroy"/>
</beans>
and Ticket class is below
package com.vaannila;
public class Ticket {
private String ticketNo="";
public String getTicketNo() {
return ticketNo;
}
public void setTicketNo(String ticketNo) {
this.ticketNo = ticketNo;
}
public void display()
{
System.out.println("Your Ticket No. is"+ ticketNo);
}
public void init()
{
System.out.println("Bean is ready You can use it now");
}
public void destroy()
{
System.out.println("Bean is going to destroy");
}
}
The out put is giving for init method but not for destroy method..
If i changed the init-method and destroy-method as default as below it is giving error in destroying the bean called "helloWorld"
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-init-method="init" default-destroy-method="destroy">
<bean id="helloWorld" class="com.vaannila.HelloWorld">
<property name="message" value="Hello World!"></property>
</bean>
<bean id="ticket" class="com.vaannila.Ticket"
scope="prototype"/>
</beans>
When a bean is defined as prototype, the bean container creates new instances of this been whenever it is asked for that bean. That's the idea behind prototype-scoped beans.
After they are created, the container gives up responsibility for the bean. It cannot know if you are still holding a reference to it, or when is the moment you drop the last reference. This is true even after the container is closed. (The container is not the garbage collector.) So it cannot possibly know when is the right moment to call the destroy method.
If you need deinitialization for your ticket, you will have to call such a method from your code directly I think (assuming that it makes no sense to have singleton tickets).
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?