異步消息
- 短信系統
- 引入JMS java message service,java消息服務
- 點對點式,point to point (一個系統的消息發佈到指定的另外一個系統)
- 發佈訂閱 publish / subscribe(一個系統約定將消息發佈到 一個主題中topic中,各個系統就能夠通過訂閱 這個主題,根據發送過來的信息 處理對應的業務。)
- 發佈 訂閱 模式 常用。
- 傳統的 ActiveMQ 和 分佈式的 kafka
- 還有AMQP一些實現的 ,比較常用的 rabbitMQ
jms實例,Active MQ
- 用戶名 密碼 都是 admin
引入pom
<!--依賴於連接池,這樣就可以啓用JMS連接池了 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
配置 mq
# ActiveMQ地址
spring.activemq.broker-url=tcp://localhost:61616
# 配置用戶名和密碼
spring.activemq.user=admin
spring.activemq.password=admin
# 是否使用發佈訂閱模式,默認是爲false,即是用的是點對點的模式
spring.jms.pub-sub-domain=true
# 默認目的地址
spring.jms.template.default-destination=activemq.default.destination
# 是否啓用連接池
spring.activemq.pool.enabled=true
# 連接池最大連接數配置
spring.activemq.pool.max-connections=50
# 讓activeMQ信任User類,配置信任列表
#spring.activemq.packages.trusted=com.springboot.chapter13.pojo,java.lang
spring.activemq.packages.trust-all=true #信任所有
- JMS連接工廠,連接池,和 JmsTemplate
- JmsTemplate
- Spring 4.1 提供 @JmsListener 接收信息
具體使用的service
// ActiveMQ服務接口
public interface ActiveMqService {
// 發送消息
public void sendMsg(String message);
// 接收消息
public void receiveMsg(String message);
}
@Service
public class ActiveMqServiceImpl implements ActiveMqService {
// 注入由Spring Boot自動生產的jmsTemplate
@Autowired
private JmsTemplate jmsTemplate = null;
/*@Value("${spring.jms.template.default-destination}")
private String defaultDestination = null;*/
@Override
public void sendMsg(String message) {
System.out.println("發送消息【" + message + "】");
jmsTemplate.convertAndSend(message);
// 自定義發送地址
// jmsTemplate.convertAndSend("your-destination", message);
}
@Override
// 使用註解,監聽地址發送過來的消息
@JmsListener(destination = "${spring.jms.template.default-destination}")
public void receiveMsg(String message) {
System.out.println("接收到消息:【" + message + "】");
}
}
- convertAndSend 發送消息的方法
- convert 轉換,默認爲 SimpleMessageConverter
- 如果使用 SerializerMessageConverter 或 Jackson2JsonMessageConverter,只需要配置JmsTemplate 的 setMessageConverter
發送實體類
public class User implements Serializable {
private static final long serialVersionUID = 8081849731640304905L;
private Long id;
private String userName = null;
private String note = null;
public User(Long id, String userName, String note) {
this.id = id;
this.userName = userName;
this.note = note;
}
}
public interface ActiveMqUserService {
public void sendUser(User user);
public void receiveUser(User user);
}
@Service
public class ActiveMqUserServiceImpl implements ActiveMqUserService {
// 注入由Spring Boot自動生產的jmsTemplate
@Autowired
private JmsTemplate jmsTemplate = null;
// 自定義地址
private static final String myDestination = "my-destination";
@Override
public void sendUser(User user) {
System.out.println("發送消息【" + user + "】");
// 使用自定義地址發送對象
jmsTemplate.convertAndSend(myDestination, user);
}
@Override
// 監控自定義地址
@JmsListener(destination = myDestination)
public void receiveUser(User user) {
System.out.println("接收到消息:【" + user + "】");
}
}
action
@Controller
@RequestMapping("/activemq")
public class ActiveMqController {
// 注入服務對象
@Autowired
private ActiveMqService activeMqService = null;
// 注入服務對象
@Autowired
private ActiveMqUserService activeMqUserService = null;
// 測試普通消息的發送
@ResponseBody
@GetMapping("/msg")
public Map<String, Object> msg(String message) {
activeMqService.sendMsg(message);
return result(true, message);
}
// 測試User對象的發送
@ResponseBody
@GetMapping("/user")
public Map<String, Object> sendUser(Long id,
String userName, String note) {
User user = new User(id, userName, note);
activeMqUserService.sendUser(user);
return result(true, user);
}
private Map<String, Object> result(Boolean success, Object message) {
Map<String, Object> result = new HashMap<>();
result.put("success", success);
result.put("message", message);
return result;
}
}
@Data
public class ResultDTO<T> {
private Integer code;
private String msg;
private Boolean ifsuccess = false;
private T result;
}
使用AMQP——RabbitMQ
- amqp是常用的消息協議
- amqp是一個 提供統一消息服務的應用層 標準協議
- 基於此協議的 客戶端 與 消息中間件 可傳遞消息。
引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置Spring Boot
#RabbitMQ 配置
#RabbitMQ 服務器地址
spring.rabbitmq.host=localhost
#RabbitMQ 端口
spring.rabbitmq.port=5672
#RabbitMQ 用戶
spring.rabbitmq.username=admin
#RabbitMQ 密碼
spring.rabbitmq.password=123456
#是否確認發送的消息已經被消費
spring.rabbitmq.publisher-confirms=true
#RabbitMQ 的消息隊列名稱,由它發送字符串
rabbitmq.queue.msg=spring-boot-queue-msg
#RabbitMQ 的消息隊列名稱,由它發送用戶對象
rabbitmq.queue.user=spring-boot-queue-user
- 最後兩個是自定義的配置屬性、
- 自定義兩個消息隊列的名稱
- publisher-confirms 意味着 發送消息方可監聽 發送消息到消費端是否成功
- 如果成功 則會 根據設置 進行回調。
創建消息隊列
導入此包:org.springframework.amqp.core;
// 消息隊列名稱
@Value("${rabbitmq.queue.msg}")
private String msgQueueName = null;
// 用戶隊列名稱
@Value("${rabbitmq.queue.user}")
private String userQueueName = null;
@Bean
public Queue createQueueMsg() {
// 創建字符串消息隊列,boolean值代表是否持久化消息
return new Queue(msgQueueName, true);
}
@Bean
public Queue createQueueUser() {
// 創建用戶消息隊列,boolean值代表是否持久化消息
return new Queue(userQueueName, true);
}
用service 使用MQ
public interface RabbitMqService {
// 發送字符消息
public void sendMsg(String msg);
// 發送用戶消息
public void sendUser(User user);
}
@Service
public class RabbitMqServiceImpl
// 實現ConfirmCallback接口,這樣可以回調
implements ConfirmCallback, RabbitMqService {
@Value("${rabbitmq.queue.msg}")
private String msgRouting = null;
@Value("${rabbitmq.queue.user}")
private String userRouting = null;
// 注入由Spring Boot自動配置的RabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate = null;
// 發送消息
@Override
public void sendMsg(String msg) {
System.out.println("發送消息: 【" + msg + "】");
// 設置回調
rabbitTemplate.setConfirmCallback(this);
// 發送消息,通過msgRouting確定隊列
rabbitTemplate.convertAndSend(msgRouting, msg);
}
// 發送用戶
@Override
public void sendUser(User user) {
System.out.println("發送用戶消息: 【" + user + "】");
// 設置回調
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.convertAndSend(userRouting, user);
}
// 回調確認方法
@Override
public void confirm(CorrelationData correlationData,
boolean ack, String cause) {
if (ack) {
System.out.println("消息成功消費");
} else {
System.out.println("消息消費失敗:" + cause);
}
}
}
- 實現 confirmCallback,可以作爲 MQ 的生產者的回調類
- setConfirmCallback(this) 設置了回調對象爲 當前對象
- 發送消息後,當消費者 得到消息時,它就會調用 confirm方法
- convertAndSend 轉換 和 發送消息
- 通過 SimpleMessageConvert對象轉換(默認)
- convertAndSend(msgRouting, msg) 消息隊列的名稱
MQ接收器
//這是一個類
@Component
public class RabbitMessageReceiver {
// 定義監聽字符串隊列名稱
@RabbitListener(queues = { "${rabbitmq.queue.msg}" })
public void receiveMsg(String msg) {
System.out.println("收到消息: 【" + msg + "】");
}
// 定義監聽用戶隊列名稱
@RabbitListener(queues = { "${rabbitmq.queue.user}" })
public void receiveUser(User user) {
System.out.println("收到用戶信息【" + user + "】");
}
}
action
@RestController
@RequestMapping("/rabbitmq")
public class RabbitMqController {
// 注入Spring Boot自定生成的對象
@Autowired
private RabbitMqService rabbitMqService = null;
@GetMapping("/msg") // 字符串
public Map<String, Object> msg(String message) {
rabbitMqService.sendMsg(message);
return resultMap("message", message);
}
@GetMapping("/user") // 用戶
public Map<String, Object> user(Long id, String userName, String note) {
User user = new User(id, userName, note);
rabbitMqService.sendUser(user);
return resultMap("user", user);
}
// 結果Map
private Map<String, Object> resultMap(String key, Object obj) {
Map<String, Object> result = new HashMap<>();
result.put("success", true);
result.put(key, obj);
return result;
}
}
docker啓動mq
docker search rabbitmq:management
docker pull rabbitmq:management
docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 rabbitmq:managemen
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management
–hostname:指定容器主機名稱
–name:指定容器名稱
-p:將mq端口號映射到本地
- 賬號密碼guest,guest
測試
發送消息: 【測試的消息內容】
收到消息: 【測試的消息內容】
消息成功消費 (// 回調確認方法 )
發送用戶消息: 【com.hua.testj.pojo.User@1b52a6be】
收到用戶信息【com.hua.testj.pojo.User@2fa71c3b】
消息成功消費