前面章节分别介绍了怎样创建连接、声明交换器、声明队列、发送消息和消费消息。本章节将介绍 RabbitMQ 程序开发的最后一步,那就是关闭连接,释放资源。它包含释放信道(Channel)、连接(Connection),代码如下:
channel.close(); connection.close();
显示地关闭信道 Channel 是一个好习惯,但并不是必须的。在连接 Connection 关闭的时候,信道 Channel 会自动关闭。关闭资源的模板代码:
Connection connection = null; Channel channel = null; try { // 创建连接 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("127.0.0.1"); factory.setPort(5672); connection = factory.newConnection(); // 创建通道 channel = connection.createChannel(); //...业务代码 } finally { if(null != channel){ channel.close(); } if(null != connection) { connection.close(); } }
AMQP 中 Connection 和 Channel 采用同样的方式来管理网络失败、内部错误和显示地关闭连接。Connection 和 Channel 具备如下声明周期:
Open:开启状态,代表当前对象可以使用。
Closing:正在关闭状态,当前对象被显示地通知调用关闭方法(shutdown),这样就产生了一个关闭请求让其内部对象进行相应的操作,并等待这些关闭操作的完成。
Closed:已经关闭状态,当前对象已经接收到所有的内部对象已完成关闭动作的通知,并且其也关闭了自身。
注意:不论程序正常调用关闭方法、还是客户端异常,甚至发生了网络异常。最终,Connection 和 Channel 都会成为 Closed 状态。
在 Connection 和 Channel 中,与关闭相关的方法如下:
addShutdownListener(ShutdownListener listener):添加关闭监听器。
removeShutdownListener(ShutdownListener listener):移除关闭监听器。
当 Connection 或者 Channel 的状态转变为 Closed 的时候会调用通过 addShutdownListener() 方法添加的 ShutdownListener 监听器。如果将一个 ShutdownListener 注册到一个已经处于 Closed 状态的 Connection 或者 Channel 对象时,会立刻调用 ShutdownListener 监听器。
下面是一些关闭辅助方法:
getCloseReason():方法可以让你知道对象关闭的原因。
isOpen():检测对象当前是否处于开启状态。
close(int closeCode, String closeMessage):方法显示地通知当前对象执行关闭操作。
ShutdownListener 监听器的使用方法示例代码如下:
// 创建连接 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("127.0.0.1"); factory.setPort(5672); Connection connection = factory.newConnection(); // 添加监听器 connection.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { System.out.println("Connection Closed"); } }); // 创建通道 Channel channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "topic"); // 添加监听器 channel.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { System.out.println("Channel Closed"); } }); // 发送消息 System.out.println("[Send] Sending Message..."); byte[] msg = ("hello wrold " + System.currentTimeMillis()).getBytes(); channel.basicPublish(EXCHANGE_NAME, "www.hxstrive.com", null, msg); System.out.println("[Send] msg = " + new String(msg));
运行上面代码,输出如下:
[Receive] Waiting Message... [Send] Sending Message... [Send] msg = hello wrold 1645455555718 [Receive] Receive Message :: hello wrold 1645455555718 Channel Closed Connection Closed
当触发 ShuwdownListener 时,可以获取到 ShutdownSignalException,ShutdownSignalException 中包含了关闭的原因,这些可以通过调用 getCloseReason() 方法获取。代码如下:
channel.getCloseReason(); connection.getCloseReason();
调用上面代码,输出信息如下:
Channel Closed cause: com.rabbitmq.client.ShutdownSignalException: clean connection shutdown; protocol method: #method<connection.close>(reply-code=200, reply-text=OK, class-id=0, method-id=0) [Receive] Receive Message :: hello wrold 1645455964149 Connection Closed cause: com.rabbitmq.client.ShutdownSignalException: clean connection shutdown; protocol method: #method<connection.close>(reply-code=200, reply-text=OK, class-id=0, method-id=0)
ShutdownSignalException 提供了多个方法来分析关闭的原因,方法如下:
isHardError():可以知道是 Connection 还是 Channel 的错误。如果返回 true,则表示 Connection 错误。如果返回 false,则表示 Channel 错误。
getReason():可以获取 cause 相关的信息。
上面方法的使用示例,代码如下:
// 创建连接 ConnectionFactory factory = new ConnectionFactory(); factory.setHost("127.0.0.1"); factory.setPort(5672); connection = factory.newConnection(); final Connection finalConn = connection; connection.addShutdownListener(new ShutdownListener() { public void shutdownCompleted(ShutdownSignalException cause) { System.out.println("Connection Closed cause: " + finalConn.getCloseReason()); if(cause.isHardError()) { System.out.println("Connection error,cause = " + cause.getReason()); } else { System.out.println("Channel error,cause = " + cause.getReason()); } } });