1:初识RabbitMQ

RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,RabbitMQ是使用Erlang语言来编写的,并且RabbitMQ是基于AMQP协议的。

2:AMQP协议模型:

3:RabbitMQ的整体架构

4:RabbitMQ核心概念

    • Server:又称Broker,接受客户端的连接,实现AMQP实体服务
    • Connection:连接,应用程序与Broker的网络连接
    • Channel:网络信道

      几乎所有的操作都在Channel中进行
      Channel是进行消息读写的通道
      客户端可建立多个Channel
      每个Channel代表一个会话任务

    • Message:消息

      服务器和应用程序之间传送的数据,由Properties和Body组成
      Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性
      Body则就是消息体内容

    • Virtual host:虚拟机

      用于进行逻辑隔离,最上层的消息路由
      一个Virtual host里面可以有若干个Exchange和Queue
      同一个Virtual host里面不能有相同名称的Exchange或Queue

    • Exchange:交换机,接收消息,根据路由键转发消息到绑定的队列
    • Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key
    • Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息
    • Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者

5:RabbitMQ消息的流转过程

6:引入依赖 以及生产端的相关配置

 <!--RabbitMQ依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
# RabbitMQ配置
spring.rabbitmq.addresses=192.168.0.105:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=15000 # Server配置
server.servlet.context-path=/
server.port=8080
spring.http.encoding.charset=UTF-8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.default-property-inclusion=NON_NULL

7: 订单对象

public class Order implements Serializable{

    private static final long serialVersionUID = 6771608755338249746L;

    private String id;

    private String name;
/**
* 存储消息发送的唯一标识
*/
private String messageId;
}

8:生产端向消息队列发送消息

private RabbitTemplate rabbitTemplate;

@Autowired
public OrderSender(
RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void send(Order order) throws Exception {

    CorrelationData correlationData = new CorrelationData();
correlationData.setId(order.getMessageId()); // exchange:交换机
// routingKey:路由键
// message:消息体内容
// correlationData:消息唯一ID
this.rabbitTemplate.convertAndSend("order-exchange", "order.a", order, correlationData);
}
Order order = new Order();
order.setId("201809062009010001");
order.setName("测试订单1");
order.setMessageId(System.currentTimeMillis() + "$" + UUID.randomUUID().toString().replaceAll("-",""));
this.orderSender.send(order);

9:消费端相关配置

# RabbitMQ连接配置
spring.rabbitmq.addresses=192.168.0.105:5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.connection-timeout=15000
# RabbitMQ消费配置
# 基本并发:5
spring.rabbitmq.listener.simple.concurrency=5
# 最大并发:10
spring.rabbitmq.listener.simple.max-concurrency=10
# 签收模式:手动签收
spring.rabbitmq.listener.simple.acknowledge-mode=manual
# 限流策略:同一时间只有1条消息发送过来消费
spring.rabbitmq.listener.simple.prefetch=1 # Server配置
server.servlet.context-path=/
server.port=8082 spring.http.encoding.charset=UTF-8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
spring.jackson.default-property-inclusion=NON_NULL

10:消费端消费消息

@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理

@Component
public class OrderReceiver { /**
* 接收消息
*
* @param order 消息体内容
* @param headers 消息头内容
* @param channel 网络信道
* @throws Exception 异常
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = "order-queue",durable = "true"),
exchange = @Exchange(name = "order-exchange",type = "topic"),
key = "order.*"
))
@RabbitHandler
public void onOrderMessage(@Payload Order order, @Headers Map<String, Object> headers, Channel channel) throws Exception {
// 消费者操作
System.out.println("收到消息:");
System.out.println("订单信息:" + order.toString()); // 手动签收消息
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicAck(deliveryTag, false);
}
}

11:保证100%消息投递

12:mybatis相关依赖

<!--MyBatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.24</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.github.miemiedev</groupId>
<artifactId>mybatis-paginator</artifactId>
<version>1.2.17</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency> 13:rabbitmq采用消息确认模式
# 采用消息确认模式
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true 14:mysql相关配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root mybatis.type-aliases-package=com.myimooc.rabbitmq.ha.dao.mapper
mybatis.mapper-locations=classpath:com/  /mapper/*.xml

数据源druid.properties配置
##下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小、最小、最大
druid.initialSize=1
druid.minIdle=1
druid.maxActive=300
# 获取连接等待超时时间(单位:毫秒)
druid.maxWait=60000
# 间隔多久进行一次检测,检测需要关闭的空闲连接(单位:毫秒)
druid.timeBetweenEvictionRunsMillis=60000
# 一个连接在池中最小生存的时间(单位:毫秒)
druid.minEvictableIdleTimeMillis=300000
druid.validationQuery=SELECT 1 FROM DUAL
druid.testWhileIdle=true
druid.testOnBorrow=false
druid.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
druid.poolPreparedStatements=true
druid.maxOpenPreparedStatements=20
# 监控统计拦截的filters,去掉后监控界面sql无法统计,wall用于防火墙
druid.filters=stat,wall,log4j
# 通过connectionProperties属性来打开mergeSQL功能:慢SQL记录
druid.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
druid.useGlobalDataSourceStat=true
DruidDataSourceSettings 类
@Component
@PropertySource("classpath:druid.properties")
public class DruidDataSourceSettings { @Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password; @Value("${druid.initialSize}")
private Integer initialSize;
@Value("${druid.minIdle}")
private Integer minIdle;
@Value("${druid.maxActive}")
private Integer maxActive;
@Value("${druid.maxWait}")
private Long maxWait; @Value("${druid.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis; @Value("${druid.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${druid.validationQuery}")
private String validationQuery;
@Value("${druid.testWhileIdle}")
private Boolean testWhileIdle;
@Value("${druid.testOnBorrow}")
private Boolean testOnBorrow;
@Value("${druid.testOnReturn}")
private Boolean testOnReturn; @Value("${druid.poolPreparedStatements}")
private Boolean poolPreparedStatements;
@Value("${druid.maxOpenPreparedStatements}")
private Integer maxOpenPreparedStatements; @Value("${druid.filters}")
private String filters;
@Value("${druid.connectionProperties}")
private String connectionProperties;
@Value("${druid.useGlobalDataSourceStat}")
private Boolean useGlobalDataSourceStat; public String getDriverClassName() {
return driverClassName;
} public String getUrl() {
return url;
} public String getUsername() {
return username;
} public String getPassword() {
return password;
} public Integer getInitialSize() {
return initialSize;
} public Integer getMinIdle() {
return minIdle;
} public Integer getMaxActive() {
return maxActive;
} public Long getMaxWait() {
return maxWait;
} public Long getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
} public Long getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
} public String getValidationQuery() {
return validationQuery;
} public Boolean getTestWhileIdle() {
return testWhileIdle;
} public Boolean getTestOnBorrow() {
return testOnBorrow;
} public Boolean getTestOnReturn() {
return testOnReturn;
} public Boolean getPoolPreparedStatements() {
return poolPreparedStatements;
} public Integer getMaxOpenPreparedStatements() {
return maxOpenPreparedStatements;
} public String getFilters() {
return filters;
} public Properties getConnectionProperties() {
Properties properties = new Properties();
String[] entrys = connectionProperties.split(";");
for (String entry : entrys) {
String[] split = entry.split("=");
properties.setProperty(split[0],split[1]);
}
return properties;
} public Boolean getUseGlobalDataSourceStat() {
return useGlobalDataSourceStat;
}
}
DruidDataSourceConfig 类
@Configuration
@EnableTransactionManagement
public class DruidDataSourceConfig { @Bean
public DataSource dataSource(DruidDataSourceSettings druidSettings) throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(druidSettings.getDriverClassName());
dataSource.setUrl(druidSettings.getUrl());
dataSource.setUsername(druidSettings.getUsername());
dataSource.setPassword(druidSettings.getPassword()); dataSource.setInitialSize(druidSettings.getInitialSize());
dataSource.setMinIdle(druidSettings.getMinIdle());
dataSource.setMaxActive(druidSettings.getMaxActive());
dataSource.setTimeBetweenEvictionRunsMillis(druidSettings.getTimeBetweenEvictionRunsMillis());
dataSource.setMinEvictableIdleTimeMillis(druidSettings.getMinEvictableIdleTimeMillis());
dataSource.setValidationQuery(druidSettings.getValidationQuery()); dataSource.setTestWhileIdle(druidSettings.getTestWhileIdle());
dataSource.setTestOnBorrow(druidSettings.getTestOnBorrow());
dataSource.setTestOnReturn(druidSettings.getTestOnReturn());
dataSource.setPoolPreparedStatements(druidSettings.getPoolPreparedStatements());
dataSource.setMaxPoolPreparedStatementPerConnectionSize(druidSettings.getMaxOpenPreparedStatements()); dataSource.setFilters(druidSettings.getFilters());
dataSource.setConnectProperties(druidSettings.getConnectionProperties());
return dataSource;
} @Bean
public PlatformTransactionManager transactionManager(DruidDataSourceSettings druidSettings) throws Exception {
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(this.dataSource(druidSettings));
return manager;
}
}
MybatisDataSourceConfig 类
@Configuration
public class MybatisDataSourceConfig { @Autowired
private DataSource dataSource; @Bean(name="sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// 添加XML目录
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
bean.setMapperLocations(resolver.getResources("classpath:com/bfxy/springboot/mapping/*.xml"));
SqlSessionFactory sqlSessionFactory = bean.getObject();
sqlSessionFactory.getConfiguration().setCacheEnabled(Boolean.TRUE); return sqlSessionFactory;
} catch (Exception e) {
throw new RuntimeException(e);
}
} @Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
} }
MybatisMapperScanerConfig 类
@Configuration
@AutoConfigureAfter(MybatisDataSourceConfig.class)
public class MybatisMapperScanerConfig { @Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.bfxy.springboot.mapper");
return mapperScannerConfigurer;
} }

15:消息发送者确认机制
@Component
public class OrderSender { @Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private BrokerMessageLogMapper brokerMessageLogMapper;
/**
* 回调方法:confirm确认
*/
private final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("correlationData:" + correlationData);
String messageId = correlationData.getId();
if (ack) {
// 如果confirm返回成功,则进行更新
BrokerMessageLogPO messageLogPO = new BrokerMessageLogPO();
messageLogPO.setMessageId(messageId);
messageLogPO.setStatus(Constants.OrderSendStatus.SEND_SUCCESS);
brokerMessageLogMapper.changeBrokerMessageLogStatus(messageLogPO);
} else {
// 失败则进行具体的后续操作:重试或者补偿等
System.out.println("异常处理...");
}
}
}; /**
* 发送订单
*
* @param order 订单
*/
public void send(Order order) {
// 设置回调方法
this.rabbitTemplate.setConfirmCallback(confirmCallback);
// 消息ID
CorrelationData correlationData = new CorrelationData(order.getMessageId());
// 发送消息
this.rabbitTemplate.convertAndSend("order-exchange", "order.a", order, correlationData);
} }
16:FastJson工具类
需要引入
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
public class FastJsonConvertUtils {

    private static final Logger logger = LoggerFactory.getLogger(FastJsonConvertUtils.class);

    /**
* 将对象转为JSON字符串
*
* @param obj 任意对象
* @return JSON字符串
*/
public static String convertObjectToJson(Object obj) {
try {
return JSON.toJSONString(obj);
} catch (Exception ex) {
logger.warn("将对象转为JSON字符串异常:" + ex);
throw new RuntimeException("将对象转为JSON字符串异常:" + ex.getMessage(), ex);
}
} /**
* 将JSON字符串转为对象
*
* @param message JSON字符串
* @param type 对象
* @param <T> 对象
* @return 对象实例
*/
public static <T> T convertJsonToObject(String message, Class<T> type) {
try {
return JSONObject.parseObject(message, type);
} catch (Exception ex) {
logger.warn("将JSON字符串转为对象异常:" + ex);
throw new RuntimeException("将JSON字符串转为对象异常:" + ex.getMessage(), ex);
}
} }
17:
<!--工具类依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
DateUtils.addMinutes(orderTime, 1)

18:定时任务
启用任务
@SpringBootApplication
@MapperScan("com.myimooc.rabbitmq.ha.dao.mapper")
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} } 配置定时任务
@Configuration
@EnableScheduling
public class TaskSchedulerConfig implements SchedulingConfigurer { @Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
} @Bean(destroyMethod="shutdown")
public Executor taskScheduler(){
return Executors.newScheduledThreadPool(100);
} } 定时任务相关执行代码
@Component
public class RetryMessageTask { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired
private OrderSender orderSender;
@Autowired
private BrokerMessageLogMapper brokerMessageLogMapper; /**
* 启动完成3秒后开始执行,每隔10秒执行一次
*/
@Scheduled(initialDelay = 3000, fixedDelay = 10000)
public void retrySend() {
logger.debug("重发消息定时任务开始");
// 查询 status = 0 和 timeout 的消息日志
List<BrokerMessageLogPO> pos = this.brokerMessageLogMapper.listSendFailureAndTimeoutMessage();
for (BrokerMessageLogPO po : pos) {
logger.debug("处理消息日志:{}",po);
if (po.getTryCount() >= Constants.MAX_RETRY_COUNT) {
// 更新状态为失败
BrokerMessageLogPO messageLogPO = new BrokerMessageLogPO();
messageLogPO.setMessageId(po.getMessageId());
messageLogPO.setStatus(Constants.OrderSendStatus.SEND_FAILURE);
this.brokerMessageLogMapper.changeBrokerMessageLogStatus(messageLogPO);
} else {
// 进行重试,重试次数+1
this.brokerMessageLogMapper.updateRetryCount(po);
Order reSendOrder = FastJsonConvertUtils.convertJsonToObject(po.getMessage(), Order.class);
try {
this.orderSender.send(reSendOrder);
} catch (Exception ex) {
// 异常处理
logger.error("消息发送异常:{}", ex);
}
}
}
logger.debug("重发消息定时任务结束");
}
}

RabbitMQ消息中间件极速入门与实战的更多相关文章

  1. CAS单点登录系列之极速入门于实战教程(4.2.7)

    @ 目录 一. SSO简介 1.1 单点登录定义 1.2 单点登录角色 1.3 单点登录分类 二. CAS简介 2.1 CAS简单定义 2.2 CAS体系结构 2.3 CAS原理 三.CAS服务端搭建 ...

  2. Go 语言极速入门

    本系列文章主要是记录<Go 语言实战>和<Google 资深工程师深度讲解 Go 语言>的学习笔记. Go 语言极速入门1 - 环境搭建与最简姿势Go 语言极速入门2 - 基础 ...

  3. SpringCloud系列之分布式配置中心极速入门与实践

    SpringCloud系列之分布式配置中心极速入门与实践 @ 目录 1.分布式配置中心简介 2.什么是SpringCloud Config? 3.例子实验环境准备 4.Config Server代码实 ...

  4. 多本Python极速入门最佳书籍,不可错过的Python学习资料!

    Python作为现在很热门的一门编程语言,介于Python的友好,许多的初学者都将其作为首选,为了帮助大家更好的学习Python,我筛选了2年内优秀的python书籍,个别经典的书籍扩展到5年内.   ...

  5. Knative 初体验:CICD 极速入门

    Knative 社区很早就在讨论用 Tekton 替换 Build 模块的相关事宜.Knative Build 官方已经正式说明不再建议使用 Knative Build 了. 如果你知道 Knativ ...

  6. 60 分钟极速入门 PyTorch

    2017 年初,Facebook 在机器学习和科学计算工具 Torch 的基础上,针对 Python 语言发布了一个全新的机器学习工具包 PyTorch. 因其在灵活性.易用性.速度方面的优秀表现,经 ...

  7. Docker技术入门与实战第2版-高清文字版

      Docker技术入门与实战第2版-高清文字版 下载地址https://pan.baidu.com/s/1bAoRQQlvBa-PXy5lgIlxUg 扫码下面二维码关注公众号回复100011 获取 ...

  8. Docker技术入门与实战

      Docker技术入门与实战 下载地址https://pan.baidu.com/s/1bAoRQQlvBa-PXy5lgIlxUg 扫码下面二维码关注公众号回复100011 获取分享码 本书目录结 ...

  9. 赞一个 kindle电子书有最新的计算机图书可买了【Docker技术入门与实战】

    最近对docker这个比较感兴趣,找一个比较完整的书籍看看,在z.cn上找到了电子书,jd dangdang看来要加油啊 Docker技术入门与实战 [Kindle电子书] ~ 杨保华 戴王剑 曹亚仑 ...

随机推荐

  1. SpringSecurity 3.2入门(8)自定义权限控制数据库设计

    ; -- ---------------------------- -- Table structure for t_system_authority_info -- ---------------- ...

  2. HashMap和Hashtable存放null

    Hashmap是可以放key为null的,Hashtable不能放key为null.hashtable放key为null会报空指针异常 1. hashmap put方法源码 public V put( ...

  3. Django分页解析

    分页 django中实现管理数据分页的类位于 django.core.paginator.py中 Paginator类 对列表数据进行分页处理 对象 Paginator(Post.objects.al ...

  4. java集合框架(一):HashMap

    有大半年没有写博客了,虽然一直有在看书学习,但现在回过来看读书基本都是一种知识“输入”,很多时候是水过无痕.而知识的“输出”会逼着自己去找出没有掌握或者了解不深刻的东西,你要把一个知识点表达出来,自己 ...

  5. 【数据库】2.0 MySQL入门学习(二)——如何获得MySQL以及MySQL安装

    1.0 如何获得MySQL: www.oracle.com https://dev.mysql.com/downloads/ 2.0 例如进入Oracle官网,找到MySQL: 进入页面后,切换到“资 ...

  6. vue+mock.js+element-ui模拟数据搞定分页

    效果如图: 前提是搭好vue前端框架,npm install mockjs引入mock.js 当前页全部代码如下,其他有关element-ui的引入未提到,仅作参考用 <!-- 用户管理 --& ...

  7. Shader Example

    //测试viewDir对顶点的影响Shader "Example/TestViewDir" { Properties{ _RimColor("Rim Color" ...

  8. 私网IP访问Internet

    公网.内网是两种Internet的接入方式. 内网接入方式:上网的计算机得到的IP地址是Internet上的保留地址,保留地址有3种形式: A类地址:10.0.0.0~10.255.255.255 B ...

  9. CentOS 7 使用 yum 安装 jdk 1.8

    安装之前先检查一下系统有没有自带open-jdk 命令: rpm -qa |grep java rpm -qa |grep jdk rpm -qa |grep gcj 如果没有输入信息表示没有安装. ...

  10. redis缓存技术在java中的应用

    https://blog.csdn.net/zhh1072773034/article/details/78538012