2016-08-19 531 views
1

我写了一个脚本,它使用Spring Rabbit将一些消息放在使用RabbitTemplate.convertAndSend的Rabbit队列中,然后退出。但是,即使消息已入队,Rabbit连接似乎仍可使应用程序保持活动状态。我还没有找到一种方式来清理告诉Rabbit服务器在消息排队后停止。如何在Spring Rabbit中干净地关闭RabbitTemplate?

我已经能够想到的最佳解决方案是将我的convertAndSend调用更改为convertSendAndReceive,以便我知道消息已成功排队,然后使用System.exit(0)退出。我切换到convertSendAndReceive,因为它看起来convertAndSend发生在后台线程或其他一些,因为如果我做了一些这样的调用后做一个System.exit(0),只有第一个这么多的人会成功。

注意,仅仅创造了RabbitTemplate不会导致此行为;通过其中一种“发送”方法使用它。

下面的代码说明了问题。

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; 
import org.springframework.amqp.rabbit.connection.ConnectionFactory; 
import org.springframework.amqp.rabbit.core.RabbitTemplate; 

import static issues.RabbitSettings.*; //Static fields containing my test Rabbit connection info 

public class RabbitTemplateShutdownIssue { 
    public static void main(String[] args) { 
     RabbitTemplate rabbitTemplate = createRabbitTemplate(); 
     rabbitTemplate.convertAndSend(ROUTING_KEY, "Test"); // Or convertSendAndReceive 
     // The app never exits 
    } 

    private static RabbitTemplate createRabbitTemplate() { 
     RabbitTemplate rabbitTemplate = new RabbitTemplate(getConnectionFactory()); 
     rabbitTemplate.setExchange(EXCHANGE); 
     rabbitTemplate.setMandatory(true); 
     return rabbitTemplate; 
    } 

    private static ConnectionFactory getConnectionFactory() { 
     CachingConnectionFactory connectionFactory = new CachingConnectionFactory(HOSTNAME); 
     connectionFactory.setPublisherConfirms(true); 
     connectionFactory.setVirtualHost(VIRTUAL_HOST); 
     connectionFactory.setUsername(USERNAME); 
     connectionFactory.setPassword(PASSWORD); 
     return connectionFactory; 
    } 
} 

有没有办法告诉兔子客户端关闭,理想情况下,所有消息已被列入队列?

+0

**关闭弹簧**。你正在使用一个'ApplicationContext'的Spring Bean - 这是一个PITA来处理,因为你需要按顺序关闭这些东西,这样你才不会遇到异常。简单的解决方案?正确地做! –

+0

@BoristheSpider在我的例子中没有运行Spring容器,所以没有Spring关闭。 –

+0

这完全是**我的观点。 (我现在看到,我的意思是“没有”而不是“与”) –

回答

3

如果你让Spring管理豆,你可以当你完成close()应用程序上下文。

你现在配置(无Spring上下文),你可以调用连接工厂destroy(),一切都将关闭的方式。

使用对这样的东西静态方法是抗图案;您需要将工厂存储在静态字段中,以便可以销毁模板正在使用的那个。

你需要一个确认的回调来获取兔收到发送确认。

+0

公平地说,实际的脚本是一个Groovy脚本,它执行一些基本的消息排队然后退出,而不是一个完整的生产应用程序。我只是用静态方法编写了我的示例,因为似乎使用Java比Spring更受Spring应用程序的支持。 –

+0

够公平的。您需要在模板上进行确认回调才能确认兔子收到了发送。 –

+0

连接工厂的destroy()正是我所期待的。 –