发后即忘模型:简单说就是创建了任务,放置到交换器上,让应用程序继续返回工作
如:
通知---对发生事件的描述,内容可以是日志,可以报告给管理员或者程序
批处理---针对大数据集合的工作或者转换
会自动将告警信息路由到critical队列或者rate_limit队列上
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; public class AlertWarningProducer { private static final String EXCHANGE_NAME = "alerts"; private static final String ROUTING_KEY = "critical.alert"; //private static final String ROUTING_KEY = "alert.rate_limt"; public static void main(String[] argv) { Connection connection = null; Channel channel = null; try { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("liuzhaoqiang128"); factory.setUsername("admin"); factory.setPassword("admin"); factory.setPort(5672); connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "topic",true); String message = "critical content!!!"; //String message = "rate_limt content!!!"; //消息发布 channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, message.getBytes()); System.out.println(" [x] Sent '" + ROUTING_KEY + "':'" + message + "'"); } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { try { connection.close(); } catch (Exception ignore) {} } } } }
import com.rabbitmq.client.*; import javax.mail.*; import javax.mail.Message.RecipientType; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.IOException; import java.util.Properties; import java.util.concurrent.TimeoutException; public class AlertWarningConsumer { private final static String EMAIL_RECIPIENTS="*******@163.com";//接收者 private final static String EMAIL_SENDER="*******@163.com";//发送者 private final static String EXCHANGE="alerts"; private final static String TYPE="topic"; private final static String QUEUE1="critical"; private final static String QUEUE2="rate_limt"; private final static String ROUTING_KEY1="critical.*"; private final static String ROUTING_KEY2="*.rate_limt"; /** * * @param recipients 接收人 * @param subject 发送主题 * @param msg 发送消息内容 * @throws IOException * @throws MessagingException */ public static void sendEmail(String recipients, String subject, Object msg) throws IOException, MessagingException { final Properties props = new Properties(); /* * 可用的属性: mail.store.protocol / mail.transport.protocol / mail.host / * mail.user / mail.from */ // 表示SMTP发送邮件,需要进行身份验证 props.put("mail.smtp.auth", "true"); props.put("mail.smtp.host", "smtp.163.com"); // 发件人的账号 props.put("mail.user", EMAIL_SENDER); // 访问SMTP服务时需要提供的密码 props.put("mail.password", "qiangzai123"); // 构建授权信息,用于进行SMTP进行身份验证 Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { // 用户名、密码 String userName = props.getProperty("mail.user"); String password = props.getProperty("mail.password"); return new PasswordAuthentication(userName, password); } }; // 使用环境属性和授权信息,创建邮件会话 Session mailSession = Session.getInstance(props, authenticator); // 创建邮件消息 MimeMessage message = new MimeMessage(mailSession); // 设置发件人 InternetAddress form = new InternetAddress( props.getProperty("mail.user")); message.setFrom(form); // 设置收件人 InternetAddress to = new InternetAddress(recipients); message.setRecipient(RecipientType.TO, to); // 设置邮件标题 message.setSubject(subject); // 设置邮件的内容体{"message":"告警消息邮件发送"} message.setContent(msg, "application/json;charset=UTF-8"); // 发送邮件 Transport.send(message); } public static void main(String[] args) { ConnectionFactory factory = new ConnectionFactory(); Connection connection = null; try { factory.setPort(5672); factory.setHost("liuzhaoqiang128"); factory.setUsername("admin"); factory.setPassword("admin"); connection = factory.newConnection(); //创建连接 final Channel channel = connection.createChannel(); //声明交换器队列绑定等信息 channel.exchangeDeclare(EXCHANGE, TYPE, true); channel.queueDeclare(QUEUE1, false, false, false, null); channel.queueBind(QUEUE1,EXCHANGE,ROUTING_KEY1); channel.queueDeclare(QUEUE2, false, false, false, null); channel.queueBind(QUEUE2,EXCHANGE,ROUTING_KEY2); Consumer rate_limit_notify = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String subject = "rate_limit Alert"; String msg = new String(body,"UTF-8"); try { sendEmail(EMAIL_RECIPIENTS, subject, msg); } catch (MessagingException e) { e.printStackTrace(); } System.out.println("send alert E-mail!Alert text:Recipients: " + EMAIL_RECIPIENTS+" subject: "+subject); channel.basicAck(envelope.getDeliveryTag(),false); } }; Consumer critical_notify = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String subject = "Critical Alert"; String msg = new String(body,"UTF-8"); try { sendEmail(EMAIL_RECIPIENTS, subject, msg); } catch (MessagingException e) { e.printStackTrace(); } System.out.println("send alert E-mail!Alert text:Recipients: " + EMAIL_RECIPIENTS+" subject: "+subject); channel.basicAck(envelope.getDeliveryTag(),false); } }; //消息消费 channel.basicConsume(QUEUE1,false,"critical",critical_notify); channel.basicConsume(QUEUE2,false,"rate_limit",rate_limit_notify); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }
如上图所示,可以看到一个名为"upload-pictures"的交换器,下方绑定了几个queue
其中一个使用场景,有三个任务,图片尺寸调整、奖励用户积分以及通知所有用户,这几个任务需要并行处理,因为这几个任务毫不相干,不需要等待上一个任务完成,现在想增加一个新类型的任务,譬如日志记录,只需定义新的队列绑定到upload-pictures交换器上即可
例如图片上传通过RbbitMQ发布一条元数据信息,然后让他真正执行任务的异步工作者去处理即可
部分代码实现如下:
import com.rabbitmq.client.*; public class UploadPicturePublish { private static final String EXCHANGE_NAME = "upload_pictures"; public static void main(String[] argv) { ConnectionFactory factory = new ConnectionFactory(); Connection connection = null; Channel channel = null; try { factory.setHost("liuzhaoqiang129"); factory.setUsername("admin"); factory.setPassword("admin"); factory.setPort(5672); connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME,"fanout",true,false,false,null); String jsonMessage = "{\"image_id\":123456,\"user_id\":123456,\"image_path\":\"pic_jpg\"}"; channel.basicPublish(EXCHANGE_NAME,"", MessageProperties.PERSISTENT_TEXT_PLAIN,jsonMessage.getBytes("UTF-8")); System.out.println("Send message:" + jsonMessage); Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { try { connection.close(); } catch (Exception ignore) {} } } } }
import com.alibaba.fastjson.JSON; import com.rabbitmq.client.*; import java.io.IOException; public class UploadPictureConsumer { private static final String EXCHANGE_NAME = "upload_pictures"; private static final String QUEUE="add_points"; private static final String QUEUE1="resize_pictures"; private static final String QUEUE2="notify-friends"; private static final String QUEUE3="logs"; public static void main(String[] argv) { ConnectionFactory factory = new ConnectionFactory(); Connection connection = null; Channel channel = null; try { factory.setHost("liuzhaoqiang129"); factory.setUsername("admin"); factory.setPassword("admin"); factory.setPort(5672); connection = factory.newConnection(); channel = connection.createChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "fanout", true, false, false, null); //积分消费 Consumer add_point = integrationConsumer(channel); channel.basicConsume(QUEUE,false,add_point); Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { try { connection.close(); } catch (Exception ignore) {} } } } public static Consumer integrationConsumer(final Channel channel){ channel.queueDeclare(QUEUE,false,false,false,null); channel.queueBind(QUEUE,EXCHANGE_NAME,""); //这里有一个应用场景就是可以获取元数据中的用户ID,这样可以从数据库中获取所有联系人,去通知联系人 //这里的回调函数可以动态注册 Consumer add_point = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String jsonString = new String(body,"UTF-8"); String message = JSON.parseObject(jsonString).getString("user_id"); if(message.equals("quit")){ channel.basicCancel(consumerTag); } System.out.println("Adding to points to user: " + message); channel.basicAck(envelope.getDeliveryTag(),false); } }; return add_point; } public static Consumer resizePictures(final Channel channel){ channel.queueDeclare(QUEUE1,false,false,false,null); channel.queueBind(QUEUE1,EXCHANGE_NAME,""); Consumer resize_pictures = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String jsonString = new String(body,"UTF-8"); String image_id = JSON.parseObject(jsonString).getString("image_id"); String image_path = JSON.parseObject(jsonString).getString("image_path"); System.out.println("Adding to points to user: " + image_id+"---"+image_path); channel.basicAck(envelope.getDeliveryTag(),false); } }; return resize_pictures; } }