1. ActiveMQ的连接池
ActiveMQ提供了PoolConnectionFactory、PoolConnection等实现连接池功能,连接池是供对connection、session、producer的“池”,PoolConnectionFactory的类注释说明的原因:
- <b>NOTE:</b> while this implementation does allow the creation of a collection of active consumers,
- it does not 'pool' consumers. Pooling makes sense for connections, sessions and producers, which
- are expensive to create and can remain idle a minimal cost. Consumers, on the other hand, are usually
- just created at startup and left active, handling incoming messages as they come. When a consumer is
- complete, it is best to close it rather than return it to a pool for later reuse: this is because,
- even if a consumer is idle, ActiveMQ will keep delivering messages to the consumer's prefetch buffer,
- where they'll get held until the consumer is active again.
- If you are creating a collection of consumers (for example, for multi-threaded message consumption), you
- might want to consider using a lower prefetch value for each consumer (e.g. 10 or 20), to ensure that
- all messages don't end up going to just one of the consumers. See this FAQ entry for more detail:
- http://activemq.apache.org/i-do-not-receive-messages-in-my-second-consumer.html
1)首先connection、session、producer的创建会消耗大量系统资源;
2)其次consumer有自己的机制,第二段中url中对一个问题进行了说明,其中讲到consumer的一个特性:consumer会获取全部的消息,接收消息的多少可以根据初始化缓存的大小设置,因此在大量消息发送到消费者时,消费者使用类似统一获取、统一消费的方式处理,“池”没有存在的价值。
2. 实现原理
PoolConnectionFactory
- “池”的存放
PoolConnection被一个Map对象存放,ConnectionKey作为该map的key,LinkedList作为连接存放的列表,也就是说获取连接时,首先会根据ConnectionKey获取对应的“小连接池”,再从“小连接池”LinkedList中去连接。
- 工厂类的参数值
maxmunActive:session的最大活跃值,该参数会通过ConnectionPool的createSession方法如入到Session工程类中(apache-common-pool的GenericObjectPoolFactory);
maxConnections:Map的value,LinkedList的大小,即ConnectionPool数量;
idleTimeout:线程超时时间,最后使用时间+idleTimeout<当前时间,连接关闭;
expiryTimeout:回收时间,连接创建时间+expiryTimeout<当前时间,连接关闭;
- 连接创建流程
1)判断工厂是否stop,如果stop,输出日志并返回null;
2)获取ConnectionKey;
3)根据ConnectionKey获取LinkedList;
4)如果LinkedList的大小==maxConnections,获取LinkedList的第一个连接;
5)校验连接,检验失败:a、创建新连接Connection b、通过连接创建ConnectionPool c、将ConnectionPool注入工厂;
6)将ConnectionPool放入LinkedList中;
其中创建ConnectionPool设计SessionPool的初始化。
3. 样例代码
- 创建连接
- public class MQPoolUtil {
- private static PooledConnection conn;
- public static void init() {
- String url = "failover:(tcp://192.168.174.250:61616)?initialReconnectDelay=1000&timeout=3000&startupMaxReconnectAttempts=2";
- ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
- try {
- PooledConnectionFactory poolFactory = new PooledConnectionFactory(factory);
- conn = (PooledConnection) poolFactory.createConnection();
- conn.start();
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- public static void destroy(){
- try {
- if(conn != null) {
- conn.close();
- }
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- public static PooledConnection getConn() {
- return conn;
- }
- public static void setConn(PooledConnection conn) {
- MQPoolUtil.conn = conn;
- }
- }
- 创建session及producer
- public class MQProducer extends Thread {
- public void run() {
- String topic = "MQ.TEST";
- Session session = null;
- MessageProducer producer = null;
- try {
- session = MQPoolUtil.getConn().createSession(false, Session.AUTO_ACKNOWLEDGE);
- Destination destination = session.createTopic(topic);
- System.out.println("session info ->" +session);
- producer = session.createProducer(destination);
- producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
- TextMessage message = session.createTextMessage("hello message!");
- producer.send(message);
- } catch (JMSException e) {
- e.printStackTrace();
- }
- }
- }
当执行多次后,从System.out.println中可以看出,sessionid可能是重复的,即缓存中获取了session。