springboot整合RabbitMq结合Canal使用消息的可靠投递BUG
配置文件
<dependencies>
<dependency>
<groupId>com.xpand</groupId>
<artifactId>starter-canal</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
</dependencies>
application.yml
spring:
rabbitmq:
password: root # 密码
username: root # 用户名
virtual-host: /wsl # 使用的虚拟机
host: 192.168.93.144 # ip
port: 5672 # 端口
publisher-confirms: true # 开启confirms
publisher-returns: true # 开启return
正常测试
@CanalEventListener //数据库的监听
public class BusinessListener {
//注入rabbit的模板类
@Autowired
private RabbitTemplate rabbitTemplate;
//设置comfrom的回调函数
RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (b) {
System.out.println("发送成功!");
} else {
System.err.println("发送失败!" + s);
}
}
};
rabbitTemplate.setConfirmCallback(confirmCallback);
//设置return的回调函数
rabbitTemplate.setMandatory(true); //true表示消息不丢
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
byte[] body = message.getBody();
System.out.println("消息"+new String(body));
System.out.println("错误代码:"+i);
System.out.println("错误信息:"+s);
System.out.println("交换机:"+s1);
System.out.println("路由key:"+s2);
}
});
@ListenPoint(table={"tb_ad"},schema = "changgou") //监听changgou数据库和tb_ad表
public void adUpdate(CanalEntry.EventType eventType,CanalEntry.RowData rowData){
//获取到更新后的内容
List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
for (CanalEntry.Column column : afterColumnsList) {
//判断字段是否是position字段
if("position".equals(column.getName())){
//如果是position字段就对应的内容发送消息到队列中
rabbitTemplate.convertAndSend("", RabbitConfig.AD_UPDATE,column.getValue());
}
}
}
}
数据库表更新之后第一次发送消息没有问题,之后的消息发送会出现
2020-09-11 22:21:18.776 ERROR 165368 — [pool-2-thread-1] .s.c.c.t.AbstractBasicMessageTransponder : pool-2-thread-1: Error occurred when invoke the listener’s interface! class:com.wsl.canal.listener.BusinessListener, method:adUpdate
这样一个错误
解决办法
- 在类中使用@PostConstruct init_method方法
//声明在bean创建的之后执行这个方法
@PostConstruct
public void init(){
System.out.println("init");
//设置comfrom的回调函数
RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
if (b) {
System.out.println("发送成功!");
} else {
System.err.println("发送失败!" + s);
}
}
};
rabbitTemplate.setConfirmCallback(confirmCallback);
//设置return的回调函数
rabbitTemplate.setMandatory(true); //true表示消息不丢
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
@Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
byte[] body = message.getBody();
System.out.println("消息"+new String(body));
System.out.println("错误代码:"+i);
System.out.println("错误信息:"+s);
System.out.println("交换机:"+s1);
System.out.println("路由key:"+s2);
}
});
}