消息類型\事務消息\確認機制\應用場景\消息過濾\監聽器接收
11 ActiveMQ消息類型
1、TextMessage 文本消息:攜帶一個java.lang.String作爲有效數據(負載)的消息,可用於字符串類型的信息交換;
2、ObjectMessage 對象消息:攜帶一個可以序列化的Java對象作爲有效負載的消息,可用於Java對象類型的信息交換;
3、MapMessage 映射消息:攜帶一組鍵值對的數據作爲有效負載的消息,有效數據值必須是Java原始數據類型(或者它們的包裝類)及String。即:byte, short, int, long, float, double, char, boolean, String
4、BytesMessage 字節消息 :攜帶一組原始數據類型的字節流作爲有效負載的消息;
5、StreamMessage 流消息:攜帶一個原始數據類型流作爲有效負載的消息,它保持了寫入流時的數據類型,寫入什麼類型,則讀取也需要是相同的類型;
public class QueueSender {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageProducer producer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Order order = new Order();
order.setOrderId("123");
order.setName("訂單");
order.setPrice("123.22");
Message message = session.createObjectMessage(order);
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息生產者
producer = session.createProducer(destination);
//7、發送消息
producer.send(message);
} catch (Exception e) {
} finally {
connection.close();
producer.close();
session.close();
}
}
}
ublic class QueueReceiver {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageConsumer messageConsumer = null;
try {
List<String> list = new ArrayList<>();
list.add("java.lang");
list.add("com.jms.type");
//必須設置對象中所有的字段所在的類是受信任的,對象類必須實現序列化接口
((ActiveMQConnectionFactory) connectionFactory).setTrustedPackages(list);
//2、創建一個連接
connection = connectionFactory.createConnection();
//接收消息多一個步驟:把連接啓動
connection.start();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createObjectMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息消費者
messageConsumer = session.createConsumer(destination);
//7、接收消息:receive方法是一個阻塞方法,它會一直等待,直到接收到消息
// receive(Long 超時毫秒數) receiveNoWait()不等待
Message receiveMessage = messageConsumer.receive();
if (receiveMessage instanceof TextMessage) {
String text = ((TextMessage) message).getText();
System.out.println("接收到的消息爲:" + text);
} else if (receiveMessage instanceof ObjectMessage) {
Order order = (Order) ((ObjectMessage) receiveMessage).getObject();
System.out.println(order.getOrderId());
System.out.println(order.getName());
System.out.println(order.getPrice());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.close();
messageConsumer.close();
session.close();
}
}
}
123
訂單
123.22
Process finished with exit code 0
12 ActiveMQ事務消息和非事務消息
消息分爲事務消息和非事務消息:
1、事務消息:創建會話Session使用transacted=true
connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
2、非事務消息:創建會話Session使用transacted=false
connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
事務消息必須在發送和接收完消息後顯式地調用session.commit();
事務性消息,不管設置何種消息確認模式,都會自動被確認;
public class QueueSender {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageProducer producer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createTextMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息生產者
producer = session.createProducer(destination);
//7、發送消息
producer.send(message);
//8、session會話需要提交事務,如果不提交消息不能發出,確認方式對事務型消息不起作用
session.commit();
} catch (Exception e) {
} finally {
producer.close();
session.close();
connection.close();
}
}
}
public class QueueReceiver {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageConsumer messageConsumer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//接收消息多一個步驟:把連接啓動
connection.start();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createTextMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息消費者
messageConsumer = session.createConsumer(destination);
//7、接收消息:receive方法是一個阻塞方法,它會一直等待,直到接收到消息
// receive(Long 超時毫秒數) receiveNoWait()不等待
Message receiveMessage = messageConsumer.receive();
//8、會話提交事務,如果不提交,消息不會銷燬,會導致重複接收
session.commit();
if (receiveMessage instanceof TextMessage) {
String text = ((TextMessage) message).getText();
System.out.println("接收到的消息爲:" + text);
}
} catch (Exception e) {
} finally {
messageConsumer.close();
session.close();
connection.close();
}
}
}
13 ActiveMQ消息確認機制
消息的成功消費通常包含三個階段:
(1)、客戶接收消息;
(2)、客戶處理消息;
(3)、消息被確認;
(1)、Session.AUTO_ACKNOWLEDGE;客戶(消費者)成功從receive方法返回時,或者從MessageListener.onMessage方法成功返回時,會話自動確認消息。
(2)、Session.CLIENT_ACKNOWLEDGE;客戶通過顯式調用消息的acknowledge方法確認消息。
(3)、Session. DUPS_OK_ACKNOWLEDGE ;不是必須確認,是一種“懶散的”消息確認,消息可能會重複發送,在第二次重新傳送消息時,消息頭的JMSRedelivered會被置爲true標識當前消息已經傳送過一次,客戶端需要進行消息的重複處理控制。
(4)、 Session.SESSION_TRANSACTED;事務提交併確認。 配合事務消息的
注意:
發送者如果使用AUTO_ACKNOWLEDGE機制,接收者使用CLIENT_AACKNOWLEDGE機制,
以接收者爲準。如果接收者沒有手動接收,服務端的消息不會銷燬。
14 ActiveMQ消息持久化
//設置發送的消息是否需要持久化
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);//不持久化
//持久化的,activemq發送消息默認都是持久化的
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
15 MQ技術的應用場景
1、異步處理
使用dubbo是同步的,A調用B,B馬上能返回結果,調用和被調用是在同一個線程完成的,稱爲同步,而A調用MQ只是把請求放在消息中,等待B從消息隊列中去取,然後處理將結果放在MQ中,A再過來拿結果。是一個異步的過程。
2、流量削峯
當有大量請求併發訪問時,可以先返回一個成功的結果,然後使用MQ異步進行處理,比如秒殺時下單,將訂單消息發送到MQ中,再慢慢消費,插入到訂單表中。
3、系統解耦
16 ActiveMQ消息過濾
ActiveMQ提供了一種機制,可根據消息選擇器中的標準來執行消息過濾,只接收符合過濾標準的消息;生產者可在消息中放入特有的標誌,而消費者使用基於這些特定的標誌來接收消息;
1、發送消息放入特殊標誌:message.setStringProperty(name, value);
2、接收消息使用基於特殊標誌的消息選擇器:
MessageConsumer createConsumer(Destination destination, String messageSelector);
3、消息選擇器是一個字符串,語法與數據庫的SQL相似,相當於SQL語句where條件後面的內容;
public class QueueSender {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageProducer producer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createTextMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息生產者
producer = session.createProducer(destination);
//添加消息標誌
message.setIntProperty("age",20);
message.setStringProperty("name","zhangsan");
//7、發送消息
producer.send(message);
} catch (Exception e) {
} finally {
producer.close();
session.close();
connection.close();
}
}
}
public class QueueReceiver {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageConsumer messageConsumer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//接收消息多一個步驟:把連接啓動
connection.start();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createTextMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//定一個選擇器
String selector = "age = 20 and name = 'zhangsan'";
//6、消息消費者
messageConsumer = session.createConsumer(destination,selector);
//7、接收消息:receive方法是一個阻塞方法,它會一直等待,直到接收到消息
// receive(Long 超時毫秒數) receiveNoWait()不等待
Message receiveMessage = messageConsumer.receive();
if (receiveMessage instanceof TextMessage) {
String text = ((TextMessage) message).getText();
System.out.println("接收到的消息爲:" + text);
}
} catch (Exception e) {
} finally {
messageConsumer.close();
session.close();
connection.close();
}
}
}
17 ActiveMQ接收消息方式
1、同步接收
receive()方法接收消息叫同步接收;
一個線程在工作,接收到消息後,執行結束
每次只能接收一個消息
如果想不斷地接收消息,那麼就需要寫一個while true循環
2、異步接收
使用監聽器接收消息,這種接收方式叫異步接收
兩個線程在工作,一個負責接收消息,一個負責處理消息
可以實現不間斷地接收消息,7*24接收消息(服務沒有宕機的情況下)
注意:
在同一個consumer中,我們不能同時使用這2種接收方式;
比如在使用listener的情況下,當調用receive()方法將會獲得一個Exception;
public class QueueReceiver {
public static final String BROKER_URL = "tcp://localhost:61616";
public static final String DESTINATION = "myQueue";
public static void main(String[] args) throws JMSException {
//1、創建連接工廠
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(BROKER_URL);
Connection connection = null;
Session session = null;
MessageConsumer messageConsumer = null;
try {
//2、創建一個連接
connection = connectionFactory.createConnection();
//接收消息多一個步驟:把連接啓動
connection.start();
//3、創建一個Session,第一個參數表示是否爲事務消息,第二個參數表示消息確認方式
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//4、創建消息
Message message = session.createTextMessage("Hello,ActiveMQ");
//5、消息目的地
Destination destination = session.createQueue(DESTINATION);
//6、消息消費者
messageConsumer = session.createConsumer(destination);
messageConsumer.setMessageListener(new MessageListener() {
//監聽器監聽到消息後,主動回調onMessage方法
@Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
String text = null;
try {
text = ((TextMessage) message).getText();
} catch (JMSException e) {
e.printStackTrace();
}
//省略進行業務邏輯的處理,插入數據庫,更新狀態等
System.out.println("接收到的消息爲:" + text);
}
}
});
} catch (Exception e) {
}
}
}