深入淺出boot2.0 第13章2異步消息activeMq和rabbitMq

異步消息

  • 短信系統
  • 引入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】
消息成功消費
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章