RabbitMQ学习笔记
来源:互联网 发布:mac重装系统磁盘成灰色 编辑:程序博客网 时间:2024/06/06 00:49
RabbitMQ学习笔记
闲来无事,最近学习了RabbitMQ,写了简单的工程。
下面关于MQ的信息是来自于百度百科:
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM WEBSPHERE MQ等等。
MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品。
RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
关于RabbitMQ服务器的安装这里不再阐述,有情趣者可以自行尝试或百度搜索.
RabbitMQ 官方下载地址: http://www.rabbitmq.com/download.html
下面开始阐述:
1.工程结构:
2.添加jar包
spring
rabbit-client
spring jar包的添加不再列出,这里仅列出rabbit-client的依赖:
<dependency> <groupId>rabbitmq-client</groupId> <artifactId>rabbitmq-client</artifactId> <version>3.5.6</version></dependency>
首先是ConnectionFactoryUtil.java类:
public class ConnectionFactoryUtil { /** * *返回ConnectionFactory 连接工厂 */ public static ConnectionFactory get() { ConnectionFactory cfconn = new ConnectionFactory(); cfconn.setHost("127.0.0.1"); cfconn.setPort(5672); cfconn.setUsername("admin"); cfconn.setPassword("admin"); //设置虚拟主机 cfconn.setVirtualHost("vhost1"); //设置线程池,为了避免产生意想不到的异常,这里将线程池大小设为1. //因为多个线程之间共享Channel时,有些操作会出现问题。如:可能会影响发布者对确认消息的接收 //这样设置也是和MqFactory.java类相关的,因为Channel在运行时是单例的. cfconn.setSharedExecutor(Executors.newFixedThreadPool(1)); return cfconn; }}
MqFactory.java 类:
@Component@Scope("singleton")public class MqFactory implements BeanDefinitionRegistryPostProcessor { private static Logger log = LoggerFactory.getLogger(MqFactory.class); private static Channel channel = null; private static Map<String, Boolean> hasBind = new HashMap<String, Boolean>(); /** * 获取通道 * @return * @throws IOException * @throws TimeoutException */ private Channel getConnection() throws IOException, TimeoutException { if (channel == null) { ConnectionFactory factory = ConnectionFactoryUtil.get(); channel = factory.newConnection().createChannel(); } return channel; } /** * 发布消息 * @param msg 发布的对象(消息) */ public void publishMessage(Object msg) { try { //队列名(自定义) String queueName = "admin"; //交换机名(自定义) String exchange = "optimus_exchange"; //路由key String routingKey = queueName + "_routingKey"; Channel channel = getConnection(); //声明交换机 channel.exchangeDeclare(exchange, "direct", true); //声明队列 channel.queueDeclare(queueName, true, false, false, null); //将队列和交换机绑定 channel.queueBind(queueName, exchange, routingKey); //序列化 byte[] buf = ObjectUtil.serializeJdk(msg); //发布消息 //MessageProperties.PERSISTENT_TEXT_PLAIN 消息属性 channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, buf); } catch (Exception e) { log.error(e.getMessage(), e); try { channel = null; hasBind.clear(); Thread.sleep(2000); } catch (Exception e2) { } } } //ioc 容器 private ConfigurableListableBeanFactory factory; // MqConsumer 所有的实现类 private static List<MqConsumer> queueList = new ArrayList<>(); //线程池 private static ExecutorService workers = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); //MqFactory初始化方法 //获取MqConsumer实现类,调用消费消息的方法. public void init() { queueList.clear(); Map<String, MqConsumer> map = factory.getBeansOfType(MqConsumer.class); for (Map.Entry<String, MqConsumer> entry : map.entrySet()) { MqConsumer consume = entry.getValue(); queueList.add(consume); } /** * MqFactory仅是一个简单的实现,交换机和队列都只有一个,且是一对一绑定的 * * 此方法是发布着发布消息成功后,消费者进行消费消息 */ doConsumerTask(queueList); } private void doConsumerTask(final List<MqConsumer> consumerList) { //用了两个死循环 //第一个是为了做到获取连接失败或成功消费消息后,仍继续连接队列消费消息. //第二个是为了将发布者发布的消息,发送给所有关注了对应队列的消费者(实现了MqConsumer实现类) //这里只有一个队列,没有复杂的模块划分,所有这里的实现简单一些 workers.submit(new Runnable() { @Override public void run() { while (true) { try { ConnectionFactory connFactory = ConnectionFactoryUtil.get(); Connection conn = connFactory.newConnection(); Channel channel = null; QueueingConsumer consumer = null; try { channel = conn.createChannel(); channel.basicQos(1); consumer = new QueueingConsumer(channel); channel.basicConsume("admin", false, "", false, false, null, consumer); } catch (Exception e) { System.out.println("无法连接"); try { // 暂停2秒后重连 Thread.sleep(2000); } catch (Exception e2) { } continue; } // 连接成功后,开始消费消息 while (true) { try { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); Object message = ObjectUtil.deserializeJdk(delivery.getBody()); for (MqConsumer mc : consumerList) { try { mc.comsum(message); } catch (Exception e) { log.error(e.getMessage(), e); } } // ack channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false); } catch (Exception e) { log.error("rabbitmq error", e); try { channel.abort(); conn.abort(); } catch (Exception e2) { } break; } } } catch (Exception e) { continue; } } } }); } public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException { this.factory = arg0; } public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry arg0) throws BeansException { }}
MqFactory 实现了 BeanDefinitionRegistryPostProcessor这个接口,意在将ConfigurableListableBeanFactory 它的实例注入进来. 以此来获取所有实现MqConsumer接口的类.
MqInit.java
@Servicepublic class MqInit implements InitializingBean{ @Autowired private MqFactory factory; public MqInit(){ } @Override public void afterPropertiesSet() throws Exception { this.factory.init(); }}
MqInit.java 主要是执行MqFactory实例的初始化方法的.
总结:
对于上面的代码而言:
针对特定的业务逻辑处理类,只需要将MqFactory注入进去,调用发布消息的方法,然后再实现MqConsumer接口(要交由spring来管理)。
这样在程序运行时,只要有发布者发布了消息,MqConsumer.java的实现类都能够收到消息并处理
MqConsumer.java接口是用来处理消息的.
下面是一个简单的处理,将消息直接打印出来:
@Servicepublic class ConsumerOne implements MqConsumer { @Override public void comsum(Object msg) { System.out.println(msg); }}
运行:
以Hello World为例:
public class App { public static void main( String[] args ) throws IOException, TimeoutException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:config/spring-view.xml"); MqFactory factory = context.getBean(MqFactory.class); factory.publishMessage("Hello World!!!!!!!!"); }}
输出:
大功告成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- RabbitMQ 学习笔记
- rabbitmq学习笔记一
- RabbitMQ学习笔记
- Rabbitmq学习笔记
- RabbitMQ学习笔记
- rabbitmq学习笔记
- RabbitMQ学习笔记
- RabbitMQ学习笔记
- RabbitMQ 学习笔记
- RabbitMQ学习入门笔记
- rabbitMq学习笔记(未完)
- RabbitMQ学习笔记
- rabbitmq学习笔记
- rabbitmq学习笔记
- RabbitMQ学习笔记
- RabbitMQ学习笔记
- rabbitMQ学习笔记
- RabbitMQ学习笔记
- UML总结之UML组件与配置
- Tomcat基础使用知识
- 用centOS系统时,怎么更改网卡设备名eth0
- mysql资料整理
- mysql alter table drop constraint 报错1064
- RabbitMQ学习笔记
- 2016 acm/icpc 青岛站现场赛 3道题
- 12.7 bzoj1022 [SHOI2008]小约翰的游戏John
- MP4大全
- 一,JSP2的自定义标签
- android中百度定位、城市选择列表,右侧字母展示
- LA 3695 Distant Galaxy
- esp8266读取和保存自定义参数
- PAT 1105. Spiral Matrix (螺旋输出)