注意:在更改传输协议之前,必须保证ActiveMQ没有运行!
简介
NIO Transport与常规TCP传输非常相似。不同之处在于它是使用NIO API实现的,它可以帮助提高性能和可扩展性。NIO仅是服务器端传输选项。尝试在客户端使用它将实例化常规TCP传输。
要从TCP切换到NIO,只需更改URI的方案部分。这是在代理的XML配置文件中定义的示例:
<broker>
...
<transportConnectors>
<transportConnector name="nio" uri="nio://0.0.0.0:61616"/>
</<transportConnectors>
...
</broker>
注意:如果不特别指定ActiveMQ的网络监听端口,那么这些端口都将使用BIO网络IO模型(OpenWire、STOMP、AMQPS……)。所以为了首先提高单节点的网络吞吐性能,需要明确指定Active的网络IO模型。如下所示,URL格式头以“你开头”,表示这个端口使用以TCP协议为基础的NIO网络IO模型:
适合使用NIO协议的场景:
可能有大量的Client去连接到Broker上,一般情况下,大量的Client去连接Broker是被操作系统的线程所限制的。因此,NIO的实现比TCP需要更少的线程去运行,所以建议使用NIO协议
可能对于Broker有一个很迟钝的网络传输,NIO比TCP提供更好的性能。
配置语法
nio://hostname:port?key=value
配置选项与TCP传输相同。
注意:原始NIO传输是使用OpenWire协议的tcp传输的替代品。其他网络协议,如AMQP,MQTT,Stomp等也有自己的NIO传输实现。它通常通过在协议前缀中添加“+ nio”后缀来配置,例如
mqtt+nio://localhost:1883
所有协议特定配置也应适用于NIO版本的传输。
实例(采用发布/订阅模式,Topic主题)
1、更改 activemq.xml配置文件,在<transportConnectors>标签中添加,同时注释掉tcpURL:
<transportConnector name="nio" uri="nio://localhost:61618?trace=true"/>
2、配置Spring文件,将连接URL更改为NIO,注意端口号改为61618
<?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:jms="http://www.springframework.org/schema/jms"
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
">
<!--配置包自动扫描-->
<context:component-scan base-package="com.hern.avtivemq"/>
<!--配置自动注解-->
<context:annotation-config></context:annotation-config>
<!--配置生产者-->
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<!-- ActiveMq连接工厂 -->
<property name="connectionFactory">
<!--真正可以生产Connection的ConnectionFactory,由对应的JMS服务厂商提供-->
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<!--配置ActiveMQ的Broker连接URL-->
<property name="brokerURL" value="nio://127.0.0.1:61618"/>
</bean>
</property>
<!--最大连接数-->
<property name="maxConnections" value="100"/>
</bean>
<!--配置队列Queue-->
<bean id="activeMQQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="spring-active-queue"/>
</bean>
<!--配置主题Topic-->
<bean id="activeMQTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="spring-active-topic"/>
</bean>
<!--Spring提供的JMS工具类,它可以进行消息发送、接收等-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="defaultDestination" ref="activeMQTopic"/>
<!--<property name="defaultDestination" ref="activeMQQueue"/>-->
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
</property>
</bean>
<!--配置监听-->
<bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="destination" ref="activeMQTopic"/>
<!--引用自己的监听器-->
<property name="messageListener" ref="myMessageListener"/>
<!--单条消息确认-->
<property name="sessionAcknowledgeMode" value="4"/>
</bean>
</beans>
3、生成者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
/*
* 消息生产者
* */
@Service
public class SpringMQ_Produce {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Produce springMQ_produce = (SpringMQ_Produce) applicationContext.getBean("springMQ_Produce");
//发送消息
springMQ_produce.jmsTemplate.send(session -> {
TextMessage textMessage = session.createTextMessage("---Spring整合ActiveMQ---");
System.out.println("发送的消息内容是:" + textMessage.getText());
return textMessage;
});
System.out.println("发送结束");
}
}
4、消费者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
/*
* 消息消费者
* */
@Service
public class SpringMQ_Consume {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Consume springMQ_consume = (SpringMQ_Consume) applicationContext.getBean("springMQ_Consume");
//接收消息
String result = (String) springMQ_consume.jmsTemplate.receiveAndConvert();
System.out.println("接收的消息是:" + result);
}
}
5、监听器
package com.hern.avtivemq;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@Component("myMessageListener")
public class MyMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if (message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("监听器接受内容是:" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
性能优化(采用Auto+NIO传输模式)
从5.13.0版本开始,ActiveMQ支持wire format协议检测,可以自动检测OpenWire,STOMP,AMQP和MQTT,允许为这4种类型的客户端共享一个传输。要通过NIO TCP连接配置ActiveMQ自动wire format检测,使用 auto+nio传输前缀。
AUTO传输选项可以设置的一些配置选项:
参数名称 默认值 描述
protocolDetectionTimeOut 30000 连接超时前的时间(以毫秒为单位)。这类似于maxInactivityDuration。如果客户端建立连接但没有为要检测的协议发送数据或足够的数据,则线程将等待更多数据通过套接字进入。如果代理在一段时间后未完成协议初始化,则会让代理终止连接。默认值为30秒。将默认值设置为<= 0以禁用此功能。
maxConnectionThreadPoolSize MAX_INT 此选项允许配置处理连接尝试的线程池的最大大小。如果有许多不同的客户端同时尝试连接,则降低此数字可以帮助防止代理程序耗尽线程。默认情况下,它通过设置为MAX_INT来关闭
Wire Formats配置
OpenWire是ActiveMQ使用的默认Wire Formats。它为高速消息传递提供了高效的二进制格式。可以在JMS客户端的连接URI字符串或Brokers传输绑定URI上配置OpenWire选项。
参数前缀 描述
wireFormat. 将选项应用于所有wireFormat.
wireFormat.default. 将选项应用于OpenWire的默认格式
wireFormat.stomp. 将选项应用于STOMP有线格式
wireFormat.amqp. 将选项应用于AMQP有线格式
wireFormat.mqtt. 将选项应用于MQTT有线格式
配置启用的Wire协议
默认情况下,所有wire协议都可用。这可以配置为仅通过设置属性auto来启用某些格式.protocols.
值 描述
default 启用OpenWire
amqp 启用AMQP格式
stomp 启用STOMP格式
mqtt 启用MQTT格式
仅显示启用OpenWire和STOMP的示例:
<transportConnector name="auto" uri="auto://localhost:5671?auto.protocols=default,stomp"/>
1、更改 activemq.xml配置文件,在<transportConnectors>标签中添加,这里额外设置NIO使用的线程池核心工作线程数和最大工作线程数(若以前配置了NIO传输,需要将其注释掉):
<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61608?maximumConnections=1000&
wireFormat.maxFrameSize=104857600&
org.apache.activemq.transport.nio.SelectorManager.corePoolSize=20&
org.apache.activemq.transport.nio.SelectorManager.maximumPoolSize=50" />
2、配置Spring文件,将连接URL更改为NIO,注意端口号改为61608:
<?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:jms="http://www.springframework.org/schema/jms"
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
">
<!--配置包自动扫描-->
<context:component-scan base-package="com.hern.avtivemq"/>
<!--配置自动注解-->
<context:annotation-config></context:annotation-config>
<!--配置生产者-->
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<!-- ActiveMq连接工厂 -->
<property name="connectionFactory">
<!--真正可以生产Connection的ConnectionFactory,由对应的JMS服务厂商提供-->
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<!--配置ActiveMQ的Broker连接URL-->
<property name="brokerURL" value="nio://127.0.0.1:61608"/>
</bean>
</property>
<!--最大连接数-->
<property name="maxConnections" value="100"/>
</bean>
<!--配置队列Queue-->
<bean id="activeMQQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="spring-active-queue"/>
</bean>
<!--配置主题Topic-->
<bean id="activeMQTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg index="0" value="spring-active-topic"/>
</bean>
<!--Spring提供的JMS工具类,它可以进行消息发送、接收等-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="defaultDestination" ref="activeMQTopic"/>
<!--<property name="defaultDestination" ref="activeMQQueue"/>-->
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
</property>
</bean>
<!--配置监听-->
<bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="destination" ref="activeMQTopic"/>
<!--引用自己的监听器-->
<property name="messageListener" ref="myMessageListener"/>
<!--单条消息确认-->
<property name="sessionAcknowledgeMode" value="4"/>
</bean>
</beans>
3、生成者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
/*
* 消息生产者
* */
@Service
public class SpringMQ_Produce {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Produce springMQ_produce = (SpringMQ_Produce) applicationContext.getBean("springMQ_Produce");
//发送消息
springMQ_produce.jmsTemplate.send(session -> {
TextMessage textMessage = session.createTextMessage("---Spring整合ActiveMQ---");
System.out.println("发送的消息内容是:" + textMessage.getText());
return textMessage;
});
System.out.println("发送结束");
}
}
4、消费者
package com.hern.avtivemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
/*
* 消息消费者
* */
@Service
public class SpringMQ_Consume {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");
SpringMQ_Consume springMQ_consume = (SpringMQ_Consume) applicationContext.getBean("springMQ_Consume");
//接收消息
String result = (String) springMQ_consume.jmsTemplate.receiveAndConvert();
System.out.println("接收的消息是:" + result);
}
}
5、监听器
package com.hern.avtivemq;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@Component("myMessageListener")
public class MyMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
if (message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("监听器接受内容是:" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
————————————————
版权声明:本文为「Hern(宋兆恒)」的原创文章,遵循CC 4.0 BY-SA版权协议。