ActiveMQ使用连接池实现消息的生产和消费

ActiveMQ使用连接池实现消息的生产和消费

使用背景:
应用ActiveMQ的消息队列特性来替换Timer框架的定时任务功能。 Timer定时器是单线程的,很容易出现一个任务出现异常,其余任务全部停止的问题,这就是线程阻塞问题。当然你可以使用线程池的方式实现多线程任务并发执行,但若是应用中定时任务多且逻辑复杂还要考虑内存资源的问题。 所以综合参考网上的众多资源,编写了基于ActiveMQ的连接池实现消息的产生和消费,在此作为记录。

环境搭建
在MQ的官网上下载相关版本的ActiveMQ,需要依据自己环境的jdk版本和Spring版本。本人使用的是Spring3.2,使用的ActiveMQ版本是5.9,且引入相关jar包,见截图:
在这里插入图片描述
代码实现
连接池管理类:

public class MQPoolFactory{
	private static final String USERNAME="admin";
	private static final String PASSWORD="admin";
	private static final String BROKERURL="tcp://127.0.0.1:61616";
	private static final int SESSIONCACHESIZE = 20;//session缓存大小设置
	
	private static final int INIT_CONNECTION_SIZE = 1;//初始化连接数
	private static final int MAX_CONNECTION_SIZE = 5;//最大连接数
	private static final int MAX_SESSION_SIZE = 100;//每个连接可创建的最大session数
	private static final int MIN_SESSION_SIZE = 10;//每个连接可创建的最小session数
	private static final int MAX_PRODUCER_SESSION = 10;//每个session可建的最大producer数
	private static final int MAX_CONSUMER_SESSION = 10;//每个session可建的最大consumer数
	
	private LinkedList<ConnectionPool> connectionPool  = new LinkedList<ConnectionPool>();//存放空闲连接的链表
	private LinkedList<SessionPool> sessionPools = new LinkedList<SessionPool>();

	/**
	 *  缺省设置,默认加载MQ工厂初始化方法
	 * @throws Exception 
	 */
	public MQPoolFactory() throws Exception{
		initMQFactory();
	}
	/**
	 * 初始化MQ
	 */
	public void initMQFactory() throws Exception{
		if(INIT_CONNECTION_SIZE > 0 && INIT_CONNECTION_SIZE <= MAX_CONNECTION_SIZE) {
			try {
				for(int i = 0;i<INIT_CONNECTION_SIZE;i++) {
					Connection connection = buildConnection();
					ConnectionPool connPool = new ConnectionPool();
					connPool.setConnection(connection);
					if(MIN_SESSION_SIZE > 0 && MIN_SESSION_SIZE <= MAX_SESSION_SIZE) {
						connPool.setActiveSessions(MIN_SESSION_SIZE);
						for (int j = 0; j < MIN_SESSION_SIZE; j++) {
							Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);//默认设置MQ自动检测消息是否送达
							SessionPool sessionPool = new SessionPool();
							sessionPool.setConnection(connection);
							sessionPool.setSession(session);
							sessionPools.addLast(sessionPool);
						}
					}
					connectionPool.add(connPool);
				}
			}catch(JMSException e) {
				throw new Exception("MQ初始化异常", e);
			}
		}
	}
	/**
	 * 构建方法
	 * @throws JMSException 
	 */
	private synchronized Connection buildConnection() throws JMSException {
		MqConfigBean bean = new MqConfigBean(BROKERURL, USERNAME, PASSWORD, SESSIONCACHESIZE);
		ActiveMQConnectionFactory targetFactory = new 			 ActiveMQConnectionFactory(bean.getUserName(),bean.getPassword(),bean.getBrokerURL());
		//targetFactory.setUseAsyncSend(true);//强制使用同步返回数据格式
		
		CachingConnectionFactory connectoryFacotry =  new CachingConnectionFactory();
		connectoryFacotry.setTargetConnectionFactory(targetFactory);
		connectoryFacotry.setSessionCacheSize(bean.getSessionCacheSize());//设置缓存大小,优化性能
		Connection connection = connectoryFacotry.createConnection();
		connection.start();//开启连接
		
		return connection;
	}
	/**
	 * 从连接池中获取连接
	 * @throws Exception 
	 */
	private synchronized ConnectionPool getConnectionPool() throws Exception {
		ConnectionPool connPool = null;
		if(connectionPool != null && connectionPool.size() > 0) {
			for (ConnectionPool connectionPool : connectionPool) {
					int poolSessionSize = connectionPool.getActiveSessions();//获取该连接中session活跃的会话数量
			        if (poolSessionSize < MAX_SESSION_SIZE) {//取相对会话比较少的连接
			            connPool = connectionPool;
			    }
			}
			//若当前连接池中的连接全部处于使用状态,则在不超过最大连接数的前提下添加新的连接
			if(connPool == null && connectionPool.size() < MAX_CONNECTION_SIZE) {
				try {
					Connection connection = buildConnection();
					connPool = new ConnectionPool();
					connPool.setConnection(connection);
					if(MIN_SESSION_SIZE > 0 && MIN_SESSION_SIZE <= MAX_SESSION_SIZE) {
						connPool.setActiveSessions(MIN_SESSION_SIZE);
						for (int j = 0; j < MIN_SESSION_SIZE; j++) {
							Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);//默认设置MQ自动检测消息是否送达
							SessionPool sessionPool = new SessionPool();
							sessionPool.setConnection(connection);
							sessionPool.setSession(session);
							sessionPools.addLast(sessionPool);
						}
					}
					connectionPool.add(connPool);
				}catch(JMSException e) {
					throw new Exception("getConnection方法创建Connection异常",e);
				}
			}
		}
		return connPool;
	}
	/**
	 * 获取生产者的session信息
	 */
	private SessionPool getProducerSessionPool() {
		SessionPool sesPool = null;
		if(sessionPools != null && sessionPools.size() > 0) {
			try {
				ConnectionPool connPool = getConnectionPool();
				for(SessionPool pool : sessionPools) {
					if(pool.getConnection() == connPool.getConnection()) {
						int poolProducerSize = pool.getAvailableProducer();//获取当前session中已存在的生产者的数量
						if(poolProducerSize < MAX_PRODUCER_SESSION) {//当前session中生产者较少的优先使用
							sesPool = pool;
						}
					}
				}
				//当前session资源被占满,则重新创建一个新的session
				if(sesPool == null && connPool.getActiveSessions() < MAX_SESSION_SIZE) {
					try {
						Connection conn = connPool.getConnection();
						Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
						sesPool = new SessionPool();
						sesPool.setConnection(conn);
						sesPool.setSession(session);
						sessionPools.addLast(sesPool);
					}catch(Exception e) {
						throw new Exception("getProducerSession方法创建Session异常",e);
					}
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sesPool;
	}
	
	/**
	 * 获取消费者的session信息
	 */
	private SessionPool getConsumerSessionPool() {
		SessionPool sesPool = null;
		if(sessionPools != null && sessionPools.size() > 0) {
			try {
				ConnectionPool connPool = getConnectionPool();
				for(SessionPool pool : sessionPools) {
					if(pool.getConnection() == connPool.getConnection()) {
						int poolConsumerSize = pool.getAvailableConsumer();//获取当前session中已存在的生产者的数量
						if(poolConsumerSize < MAX_CONSUMER_SESSION) {//当前session中消费者较少的优先使用
							sesPool = pool;
						}
					}
				}
				//当前session资源被占满,则重新创建一个新的session
				if(sesPool == null && connPool.getActiveSessions() < MAX_SESSION_SIZE) {
					try {
						Connection conn = connPool.getConnection();
						Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
						sesPool = new SessionPool();
						sesPool.setConnection(conn);
						sesPool.setSession(session);
						sessionPools.addLast(sesPool);
					}catch(Exception e) {
						throw new Exception("getProducerSession方法创建Session异常",e);
					}
				}
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		return sesPool;
	}
	
	/**
	 * 获取生产者的连接信息
	 * @param name 消息队列名称  messageType p2p or topic
	 * @param isVIP  可扩展  若为true则代表 当前session中无消费者和生产者
	 * @throws Exception 
	 */
	public ProducerPool getProducerPool(String name,String messageType) throws Exception{
		SessionPool sessionPool = getProducerSessionPool();
		Session session = sessionPool.getSession();
		try {
			Destination dt = null;
			if(messageType.equals(MessageTypeEnum.TOPIC.getTypeName())) {
				dt = session.createTopic(name);
			}else if(messageType.equals(MessageTypeEnum.QUEUE.getTypeName())) {
				dt = session.createQueue(name);
			}
			MessageProducer producer = session.createProducer(dt);
			ProducerPool producerPool = new ProducerPool();
			producerPool.setProducer(producer);
			producerPool.setConnection(sessionPool.getConnection());
			producerPool.setSession(session);
			producerIncreament(sessionPool);
			return producerPool;
		}catch(Exception e) {
			throw new Exception("获取生产者连接异常",e);
		}
	}
	/**
	 * 获取消费者的连接信息
	 * @param name 消息队列名称  messageType p2p or topic
	 * @param isVIP  可扩展  若为true则代表 当前session中无消费者和生产者
	 * @throws Exception 
	 */
	public ConsumerPool getConsumerPool(String name,String messageType) throws Exception{
		SessionPool sessionPool = getConsumerSessionPool();
		Session session = sessionPool.getSession();
		try {
			Destination dt = null;
			if(messageType.equals(MessageTypeEnum.TOPIC.getTypeName())) {
				dt = session.createTopic(name);
			}else if(messageType.equals(MessageTypeEnum.QUEUE.getTypeName())) {
				dt = session.createQueue(name);
			}
			MessageConsumer consumer = session.createConsumer(dt);
			ConsumerPool consumerPool = new ConsumerPool();
			consumerPool.setConsumer(consumer);
			consumerPool.setConnection(sessionPool.getConnection());
			consumerPool.setSession(session);
			consumerIncreament(sessionPool);
			return consumerPool;
		}catch(Exception e) {
			throw new Exception("获取消费者连接异常",e);
		}
	}
	/**
	 * 连接池中可用生产者加一
	 * @param sessionPool
	 */
	private void producerIncreament(SessionPool sessionPool){
		if(sessionPool!=null){
			for(SessionPool sePool : sessionPools){
				if(sePool==sessionPool){
					int cnt = sePool.getAvailableProducer();
					cnt++;
					sePool.setAvailableProducer(cnt);
				}
			}
		}
	}
	/**
	 * 连接池中可用生产者减一
	 * @param producerPool
	 */
	public void producerDecreament(ProducerPool producerPool){
		if(producerPool!=null){
			for(SessionPool sessionPool : sessionPools){
				if(sessionPool.getConnection()==producerPool.getConnection() 
						&& sessionPool.getSession()==producerPool.getSession()){
					int cnt = sessionPool.getAvailableProducer();
					cnt--;
					sessionPool.setAvailableProducer(cnt);
				}
			}
		}
	}
	/**
	 * 连接池中可用消费者加一
	 * @param sessionPool
	 */
	private void consumerIncreament(SessionPool sessionPool){
		if(sessionPool!=null){
			for(SessionPool sePool : sessionPools){
				if(sePool==sessionPool){
					int cnt = sePool.getAvailableConsumer();
					cnt++;
					sePool.setAvailableConsumer(cnt);
				}
			}
		}
	}
	/**
	 * 连接池中可用消费者减一
	 * @param consumerPool
	 */
	public void consumerDecreament(ConsumerPool consumerPool){
		if(consumerPool!=null){
			for(SessionPool sessionPool : sessionPools){
				if(sessionPool.getConnection()==consumerPool.getConnection() 
						&& sessionPool.getSession()==consumerPool.getSession()){
					int cnt = sessionPool.getAvailableConsumer();
					cnt--;
					sessionPool.setAvailableConsumer(cnt);
				}
			}
		}
	}
	/**
	 * 释放所有连接
	 * @return
	 * @throws AMQFactoryException
	 */
	public boolean disposeAll() throws Exception{
		try {
			if(sessionPools!=null && sessionPools.size()>0){
				for (SessionPool sessionPool : sessionPools) {
					sessionPool.getSession().close();
				}
				sessionPools.clear();
			}
			if(connectionPool!=null && connectionPool.size()>0){
				for(ConnectionPool connectionPool : connectionPool){
					connectionPool.getConnection().stop();
					connectionPool.getConnection().close();
				}
				connectionPool.clear();
			}
			return true;
		} catch (JMSException e) {
			throw new Exception("释放连接出错",e);
		}
	}
	/**
	 * 释放生产者连接
	 * @throws Exception 
	 */
	public void closeProducerConnection(MessageProducer producer) throws Exception {
		if(producer!=null){
			try {
				producer.close();
			} catch (JMSException e) {
				throw new Exception("释放producer连接出错",e);
			}
		}
	}
	/**
	 * 释放消费者连接
	 * @throws Exception 
	 */
	public void closeConsumerConnection(MessageConsumer consumer) throws Exception {
		if(consumer!=null){
			try {
				consumer.close();
			} catch (JMSException e) {
				throw new Exception("释放consumer连接出错",e);
			}
		}
	}
	/**
	 * 编写MQ配置bean
	 */
	@SuppressWarnings("unused")
	private static class MqConfigBean{
		private String brokerURL;
	    private String userName;
	    private String password;
	    private int sessionCacheSize;
	    
		public MqConfigBean(){
	    	
	    }
	    public MqConfigBean(String brokerURL, String userName, String password, int sessionCacheSize) {
	        this.brokerURL = brokerURL;
	        this.userName = userName;
	        this.password = password;
	        this.sessionCacheSize = sessionCacheSize;
	    }
		public String getBrokerURL() {
			return brokerURL;
		}
		public void setBrokerURL(String brokerURL) {
			this.brokerURL = brokerURL;
		}
		public String getUserName() {
			return userName;
		}
		public void setUserName(String userName) {
			this.userName = userName;
		}
		public String getPassword() {
			return password;
		}
		public void setPassword(String password) {
			this.password = password;
		}
		public int getSessionCacheSize() {
			return sessionCacheSize;
		}
		public void setSessionCacheSize(int sessionCacheSize) {
			this.sessionCacheSize = sessionCacheSize;
		}
	}
}

枚举类

public enum MessageTypeEnum {
	TOPIC("topic"),QUEUE("queue");
	
	private String typeName;
	
	MessageTypeEnum(String typeName){
		this.typeName = typeName;
	}
	
	public String getTypeName() {
		return typeName;
	}
}

消息发送管理类

public class MQPoolSender {
	public boolean sendStrMsg(AMQPoolFactory amqFactory,String name,String messageType,String msg) {
		if(amqFactory == null) {
			log.error("MQ工厂实例为null");
		}
		if("".equals(name) || name == null) {
			log.error("消息队列名称为空");
		}
		if("".equals(msg) || msg == null) {
			log.error("待发送的消息为空");
		}
		try {
			//获取生产者的连接池信息
			ProducerPool producerPool = null;
			if(onUsing) {//若内存中有则拿出来进行复用
				if(mapProPool.containsKey(name)){
					producerPool = mapProPool.get(name);
	       	  	}
			}else if(producerPool == null){
       	  		producerPool = amqFactory.getProducerPool(name,messageType);
       	  	}
			
			Session session = producerPool.getSession();
			MessageProducer producer = producerPool.getProducer();
			try {
				TextMessage textMsg = session.createTextMessage(msg);
				long time = 60 * 1000;// 延时1分钟发送
//				long period = 10 * 1000;// 每个10s  
//		        int repeat = 6;// 6次  
		        textMsg.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time);  
//		        textMsg.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, period);  
//		        textMsg.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, repeat);  
		        
				producer.send(textMsg);
				System.out.println(">>>>>>>>>>>>>>>>向消息队列"+name+"发送消息为:"+textMsg.getText());
				return true;
			}catch (JMSException e) {
				System.out.println("消息发送失败"+e);
			}finally {
					//释放生产者连接
					amqFactory.closeProducerConnection(producer);
					//连接池中的可用生产者减一
					amqFactory.producerDecreament(producerPool);
				}
			}
		}catch(Exception e) {
			System.out.println("消息发送失败"+e);
		}
		return false;
	}
}

消息接受监听管理类

public class MQReceiverListeners {
	public boolean setListener(AMQPoolFactory amqFactory,String name,Class<?> className,String messageType) {
		try {
			ConsumerPool consumerPool = amqFactory.getConsumerPool(name, messageType);
			MessageConsumer consumer = null;
			try {
				//利用反射机制实例化监听类
				DjMessageListener listener = (DjMessageListener) className.newInstance();
				consumer = consumerPool.getConsumer();
				consumer.setMessageListener(listener);
				return true;
			}catch (JMSException e) {
				System.out.println("消息监听异常"+e);
			}finally {
				amqFactory.closeConsumerConnection(consumer);
				amqFactory.consumerDecreament(consumerPool);
			}
		}catch (Exception e) {
			System.out.println("消息监听异常"+e);
		}
		return false;
	}
}

消息监听实现类

public class DjMessageListener implements MessageListener {

public void onMessage(Message message) {
	System.out.println(">>>>>>>>>>>>>>>>>>>>>监听到有消息进来");
	try {
		TextMessage textMsg = (TextMessage) message;
		String text = textMsg.getText();
		System.out.println("》》》》》》》》》》》》》》》》》》》》》》》》收到消息"+text);
	} catch (JMSException e) {
		e.printStackTrace();
	}
}

MQ消息队列调度管理类

public class MQManager{
	private static volatile MQManager instance = null;
	private MQPoolFactory amqFactory = null;
	private MQPoolSender poolSender = new MQPoolSender();
	private MQReceiverListeners poolReceiver = new MQReceiverListeners ();
	//缺省模式
	private MQManager() {
		initMQ();
	};
	/**
	 * 使用单例模式进行类实例化
	 */
     public static AMQManager getInstance() {
    	 if(instance == null) {
    		 synchronized(AMQManager.class) {
    			 if(instance == null) {
    				 instance = new AMQManager();
    			 }
    		 }
    	 }
    	 return instance;
     }
      /**
      * 使用缺省设置来初始化MQ连接
      * @param isUsePool
      */
     public void initMQ(boolean isUsePool) {
	   	 try {
	   	 		 amqFactory = new AMQPoolFactory();
	    	 }catch (Exception e) {
	    		 e.printStackTrace();
			}
     }
     /**
      * 使用连接池的方式来发送的信息
      * 
      */
     public boolean sendStrMsg(String messageNme,String messageType,String msg,boolean onUsing){
    	 return poolSender.sendStrMsg(amqFactory, messageNme, messageType, msg, onUsing);
     }
     
     /**
  	  * 使用连接池的方式设置消费者监听
      */
     public boolean setListener(String messageNme, Class<?> className,String messageType) {
    	 return poolReceiver.setListener(amqFactory, messageNme, className, messageType);
     }
}

测试:

public static void main(String[] agrs) {
	MQManager amqManager = MQManager.getInstance();
	for(int i=0;i<10;i++) {
		amqManager.sendStrMsg("testQueue", "queue", "第"+i+"个定时任务");
	}
}

测试结果:
在这里插入图片描述
总结:
之前都是直接使用MQ的工厂模式直接创建连接、生产者和消费者,这个其实在小型应用中是没什么问题的,但是在一些大型应用,且存在高并发的情况下,频繁去创建连接,会占用消耗内存资源,这次是综合参考网上诸多demo加上一些特定场景来实现的。 当然MQ也有自带的连接池,有时间会把自带的连接池详细写一下。若有不足之处,欢迎评论区批评。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值