JMS與Active MQ入門、Spring整合Active MQ

JMS與Active MQ入門

JMS是什麼

JMS(Java Messaging Service)是Java平臺上有關面向消息中間件的技術規範,實際上是一套api,它便於消息系統中的Java應用程序進行消息交換,並且通過提供標準的產生、發送、接收消息的接口簡化企業應用的開發,ActiveMQ而是這個規範的一個具體實現。JMS是一種與廠商無關的 API,用來訪問收發系統消息,它類似於JDBC.

JMS對象模型

  • 連接工廠:連接工廠負責創建一個JMS連接。
  • JMS連接:JMS連接(Connection)表示JMS客戶端和服務器端之間的一個活動的連接,是由客戶端通過調用連接工廠的方法建立的。
  • JMS會話:JMS會話(Session)表示JMS客戶與JMS服務器之間的會話狀態。JMS會話建立在JMS連接上,表示客戶與服務器之間的一個會話線程。
  • JMS目的/ Broker:客戶用來指定它生產的消息的目標和它消費的消息的來源的對象,一個消息中間件的實例。
  • JMS生產者和消費者:生產者(Message Producer)和消費者(Message Consumer)對象由Session對象創建,用於發送和接收消息。

JMS中的消息

JMS 消息由以下三部分組成:

  • 消息頭:每個消息頭字段都有相應的getter 和setter 方法。
  • 消息屬性:如果需要除消息頭字段以外的值,那麼可以使用消息屬性。
  • 消息體:JMS 定義的消息類型有TextMessage、MapMessage、BytesMessage、StreamMessage 和 ObjectMessage。ActiveMQ也有對應的實現。

JMS消息模型

上次的《基於異步消息模式的通信》中已對此有所介紹,這裏再詳細說一下:

Point-to-Point(P2P) / 點對點

    消息通過稱爲隊列的一個虛擬通道來進行交換。隊列是生產者發送消息的目的地和接受者消費消息的消息源。
    每條消息通僅會傳送給一個接受者。可能會有多個接受者在一個隊列中偵聽,但是每個隊列中的消息只能被隊列中的一個接受者消費
    消息存在先後順序。一個隊列會按照消息服務器將消息放入隊列中的順序,把它們傳送給消費者當消息已被消費時,就會從隊列頭部將它們刪除。
    每個消息只有一個消費者(Consumer)(即一旦被消費,消息就不再在消息隊列中)
    發送者發送了消息之後,不管接收者有沒有正在運行,它不會影響到消息被髮送到隊列
    接收者在成功接收消息之後需向隊列應答成功
    如果希望發送的每個消息都應該被成功處理的話,使用這個P2P模式。

Topic/ 主題(發佈訂閱(Pub/Sub) )

    消息生產者(發佈)將消息發佈到topic中,同時有多個消息消費者(訂閱)消費該消息。和點對點方式不同,發佈到topic的消息會被所有訂閱者消費
    如果你希望發送的消息可以不被做任何處理、或者被一個消息者處理、或者可以被多個消費者處理的話,那麼可以採用topic模型

消息的消費方式

  1. 同步消費:通過調用 消費者的receive 方法從目的地中顯式提取消息。receive 方法可以一直阻塞到消息到達。
  2. 異步消費:客戶可以爲消費者註冊一個消息監聽器,以定義在消息到達時所採取的動作。

Active MQ入門

Active MQ 下載與啓動

  • 下載:http://activemq.apache.org/components/classic/download/,下載後解壓
  • 啓動:運行bin目錄下的activemq.bat即可。Linux下操作類似(進入bin目錄運行./activemq start啓動,./activemq stop關閉)

    運行後在瀏覽器中訪問http://127.0.0.1:8161/admin,即可看到ActiveMQ的管理控制檯
ActiveMQ中,61616爲服務端口,8161爲管理控制檯端口。

使用原生Active MQ

新建一個maven項目,導入Active MQ的pom依賴。

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.8.0</version>
</dependency>

消息生產端

public class JmsProducer {

    /*默認連接用戶名*/
    private static final String USERNAME
            = ActiveMQConnection.DEFAULT_USER;
    /* 默認連接密碼*/
    private static final String PASSWORD
            = ActiveMQConnection.DEFAULT_PASSWORD;
    /* 默認連接地址*/
    private static final String BROKEURL
            = ActiveMQConnection.DEFAULT_BROKER_URL;
    private static final int SENDNUM = 3;

    public static void main(String[] args) {
        /* 連接工廠*/
        ConnectionFactory connectionFactory;
        /* 連接*/
        Connection connection = null;
        /* 會話*/
        Session session;
        /* 消息的目的地*/
        Destination destination;
        /* 消息的生產者*/
        MessageProducer messageProducer;

        /* 實例化連接工廠*/
        connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,
                BROKEURL);
        try {
            /* 通過連接工廠獲取連接*/
            connection = connectionFactory.createConnection();
            /* 啓動連接*/
            connection.start();
            /* 創建session
            * 第一個參數表示是否使用事務,第二次參數表示是否自動確認*/
            session = connection.createSession(false,
                    Session.AUTO_ACKNOWLEDGE);
            /* 創建一個名爲HelloWorld消息隊列*/
            //destination = session.createTopic("HelloActiveMq");
            destination = session.createQueue("HelloActiveMqQueue");
            /* 創建消息生產者*/
            messageProducer = session.createProducer(destination);
            /* 循環發送消息*/
            for(int i=0;i<SENDNUM;i++){
                String msg = "發送消息"+i+" "+System.currentTimeMillis();
                TextMessage textMessage = session.createTextMessage(msg);
                System.out.println("標準用法:"+msg);
                messageProducer.send(textMessage);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

消息消費端

public class JmsConsumer {
    /*默認連接用戶名*/
    private static final String USERNAME
            = ActiveMQConnection.DEFAULT_USER;
    /* 默認連接密碼*/
    private static final String PASSWORD
            = ActiveMQConnection.DEFAULT_PASSWORD;
    /* 默認連接地址*/
    private static final String BROKEURL
            = ActiveMQConnection.DEFAULT_BROKER_URL;

    public static void main(String[] args) {
        /* 連接工廠*/
        ConnectionFactory connectionFactory;
        /* 連接*/
        Connection connection = null;
        /* 會話*/
        Session session;
        /* 消息的目的地*/
        Destination destination;
        /* 消息的消費者*/
        MessageConsumer messageConsumer;

        /* 實例化連接工廠*/
        connectionFactory
                = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEURL);

        try {
            /* 通過連接工廠獲取連接*/
            connection = connectionFactory.createConnection();
            /* 啓動連接*/
            connection.start();
            /* 創建session*/
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            /* 創建一個名爲HelloWorld消息隊列*/
            //destination = session.createTopic("HelloActiveMq");
            destination = session.createQueue("HelloActiveMqQueue");
            /* 創建消息消費者*/
            messageConsumer = session.createConsumer(destination);
            Message message;
            while((message = messageConsumer.receive())!=null){
                System.out.println(((TextMessage)message).getText());
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }finally {
            if(connection!=null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

消息異步消費端

public class JmsConsumerAsyn {
    /*默認連接用戶名*/
    private static final String USERNAME
            = ActiveMQConnection.DEFAULT_USER;
    /* 默認連接密碼*/
    private static final String PASSWORD
            = ActiveMQConnection.DEFAULT_PASSWORD;
    /* 默認連接地址*/
    private static final String BROKEURL
            = ActiveMQConnection.DEFAULT_BROKER_URL;

    public static void main(String[] args) {
        /* 連接工廠*/
        ConnectionFactory connectionFactory;
        /* 連接*/
        Connection connection = null;
        /* 會話*/
        Session session;
        /* 消息的目的地*/
        Destination destination;
        /* 消息的消費者*/
        MessageConsumer messageConsumer;

        /* 實例化連接工廠*/
        connectionFactory
                = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEURL);

        try {
            /* 通過連接工廠獲取連接*/
            connection = connectionFactory.createConnection();
            /* 啓動連接*/
            connection.start();
            /* 創建session*/
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            /* 創建一個名爲HelloWorld消息隊列*/
            //destination = session.createTopic("HelloActiveMq");
            destination = session.createQueue("HelloActiveMqQueue");

            /* 創建消息消費者*/
            messageConsumer = session.createConsumer(destination);
            /* 設置消費者監聽器,監聽消息*/
            messageConsumer.setMessageListener(new MessageListener() {
                public void onMessage(Message message) {
                    try {
                        System.out.println(((TextMessage)message).getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

Active MQ在Spring中的使用

1、添加依賴

    首先我們先要搭建一個Spring 的maven項目。
    然後我們在pom文件中添加active mq的依賴與:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
    <version>4.3.11.RELEASE</version>
</dependency>

2、配置文件applicationContext.xml

命名空間的添加

xmlns:amq="http://activemq.apache.org/schema/core"
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd

消費者的命名空間要再額外添加如下:

xmlns:jms="http://www.springframework.org/schema/jms"
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms-4.0.xsd

ActiveMQ 連接工廠

<amq:connectionFactory id="amqConnectionFactory"
         brokerURL="tcp://127.0.0.1:61616" userName="" password="" />

Spring Caching連接工廠

<!-- Spring用於管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
      class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="amqConnectionFactory"></property>
    <property name="sessionCacheSize" value="100"></property>
</bean>

3、消息生產者配置以及代碼的編寫

Spring JmsTemplate 的消息生產者

<!-- 定義JmsTemplate的Queue類型 -->
<bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
    <constructor-arg ref="connectionFactory"></constructor-arg>
    <!-- 隊列模式-->//true爲發佈訂閱模式
    <property name="pubSubDomain" value="false"></property>
</bean>

然後便可以使用JmsTemplate

@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;

public void send(String queueName,final String message){
	jmsTemplate.send(queueName, new MessageCreator() {
		public Message createMessage(Session session) throws JMSException {
			Message msg = session.createTextMessage(message);
			//TODO  應答
			return msg;
			}
		});

3、消息消費者配置以及代碼的編寫

定義Queue監聽器

<jms:listener-container destination-type="queue" container-type="default"
                        connection-factory="connectionFactory" acknowledge="auto">
    <jms:listener destination="test.queue" ref="queueReceiver1"></jms:listener>
    <jms:listener destination="test.queue" ref="queueReceiver2"></jms:listener>
</jms:listener-container>

queueReceiver1的編寫

@Component
public class QueueReceiver1 implements MessageListener {
	public void onMessage(Message message) {
		try {
			String textMsg = ((TextMessage)message).getText();
			System.out.println("QueueReceiver1 accept msg : "+textMsg);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章