2016年10月26日 星期三

jboss eap 6.2 + jms local

練習 JBoss 的JMS...Local client呼叫

1. 要記得把 server config 切到 standalone-full.xml
(要用原本的standalone.xml也可以,但是我看就是要加很多東西,有人建議就直接跑full就好,事實上也是,跑 full 幾乎沒啥問題)
在 windows 更換啟動的指令
cd xxxxxx\jboss-eap-6.2\bin\
standalone.bat -c standalone-full.xml
 (一般直接啟用,不帶參數,就是跑 standalone.xml)


2. 如果有設定 datasource,或是什麼要定在 standalone**.xml 裡面東西的,要再下一次。
(總之,就比對一下 兩邊的 xml,大概就可以看出點什麼差別)


3. 查一下 standalone-full.xml 裡面有沒有 <mdb 這個 tag內容
理論上長成這樣
<subsystem xmlns="urn:jboss:domain:ejb3:1.4">
            ....
            <mdb>
                <resource-adapter-ref resource-adapter-name="${ejb.resource-adapter-name:hornetq-ra}"/>
                <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
            </mdb>

如果search 沒有  <mdb 就要手動新增,我一樣用 cli 語法加
/subsystem=ejb3:write-attribute(name="default-mdb-instance-pool", value="mdb-strict-max-pool")
/subsystem=ejb3:write-attribute(name="default-resource-adapter-name", value="${ejb.resource-adapter-name:hornetq-ra.rar}")

(ps:jboss 內建是 hornetq,如果要換別家的話,就要多灌lib進來才行吧)


4. 查一下 socket bind
理論上長這樣
<socket-binding-group
.....
        <socket-binding name="messaging" port="5445"/>
        <socket-binding name="messaging-group" port="0" multicast-address="${jboss.messaging.group.address:231.7.7.7}" multicast-port="${jboss.messaging.group.port:9876}"/>
        <socket-binding name="messaging-throughput" port="5455"/>
(不過這個應該 default 就有,只是看一下,知道他會把服務起在那個 port 就是)


5. 寫 jms 設定檔,webapp/META-INF/*-hornetq-jms.xml ,ex: my-hornetq-jms.xml
<?xml version="1.0" encoding="UTF-8"?>
<messaging-deployment xmlns="urn:jboss:messaging-deployment:1.0">
    <hornetq-server>
        <jms-destinations>
            <jms-queue name="MyMDBQueue">
                <entry name="/queue/MyQueue"/>
            </jms-queue>
            <jms-topic name="MyQueueMDBTopic">
                <entry name="/topic/MyTopic"/>
            </jms-topic>
        </jms-destinations>
    </hornetq-server>
</messaging-deployment>

6. 寫 Server side listener
import java.util.Date;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;

@MessageDriven(activationConfig = {
        @ActivationConfigProperty(
                propertyName = "destinationType",
                propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(
                propertyName = "destination",
                propertyValue = "queue/MyQueue") })
public class QueueListenerMDB implements MessageListener {
    public QueueListenerMDB() {
    }

    public void onMessage(Message message) {
        try {
            if (message instanceof TextMessage) {
                System.out.println("Queue: Server listener received ="+System.currentTimeMillis());
                TextMessage msg = (TextMessage) message;
                System.out.println("Message is : " + msg.getText());
            } else if (message instanceof ObjectMessage) {
                System.out.println("Queue: Server received an ObjectMessage at "+System.currentTimeMillis());
                ObjectMessage msg = (ObjectMessage) message;
                Object pojo = msg.getObject();
                System.out.println("pojo Details: "+pojo);
            } else {
                System.out.println("Not valid message for this Queue MDB");
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

7. 寫Client 驗證
(基本的 連接傳送是降子)
    QueueConnection conn;
    QueueSession session;
    Queue que;
    QueueSender send;
   
    private void connect() throws Exception {
        //
        InitialContext iniCtx = new InitialContext();
        Object tmp = iniCtx.lookup("ConnectionFactory");
        QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
        conn = qcf.createQueueConnection();
        que = (Queue) iniCtx.lookup("queue/MyQueue");
        session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
        conn.start();
    }
   
    private void stop() throws JMSException  {
        conn.stop();
        session.close();
        conn.close();
    }
   
    private void sendText(String text)  throws Exception {
        send = session.createSender(que);
        TextMessage tm = session.createTextMessage(text);
        log.info("sendRecvAsync, sent text=" + tm.getText());
        send.send(tm);
        send.close();
    }
   
    private void sendObject(Serializable obj) throws Exception {
        MessageProducer producer = session.createProducer( que );
        ObjectMessage message = session.createObjectMessage( obj );
        producer.send( message );
        send.close();
    }
   
(呼叫時使用就是照順序 open connect(session) -> session create send -> sendMessage(text/Object) -> close send -> close session)

client.connect();
client.sendText("Hi!");
client.sendObject( MyObject );
client.stop();

8. 包一包丟到JBoss 上
因為 JMS 有跑的時後看起來在 init 的時後,好像會咬住server的資源,如果不是用 shutdown的機制(直接關cmd),我碰到的是會有「存取被拒」的情況,就算是電腦關機後再開,還是會衝,大概還是就是先 正常的 shutdown 後(記得要等個幾秒),再重起 JBoss就會過去
那個 錯誤 在 log 裡會像降子(假警報,可是就是會被嚇到,明明沒動,想說是那裡又改錯了一.一|||,如果沒去看 server log 大概又會以為程式有問題...然後其實那個 war 是在deploy 成功的狀態(fail會有 xxxx.war.fail 的文字檔寫錯誤)...追log看,前面該跑的也都有跑起來,但是就是在後面會卡住)
 [javax.enterprise.resource.webcontainer.jsf.config] (ServerService Thread Pool -- 62) 正在初始化環境「/xxxxxx」的 Mojarra 2.1.19-jbossorg-1 20131024-0833
SEVERE [javax.enterprise.resource.webcontainer.jsf.config] (ServerService Thread Pool -- 62) Critical error during deployment: : com.sun.faces.config.ConfigurationException: java.util.concurrent.ExecutionException: javax.faces.FacesException: java.io.FileNotFoundException: D:\jboss-eap-6.2\standalone\tmp\vfs\temp\tempb1f1831541a362e4\xxxxxx.war-adb47e313f325e6a\xxxxxx.war-8494329521517097592.tmp (存取被拒。)


9. 其它
如果 JMS 有跑起來的話,用  cli 看 jndi-view 是有些東西的喔,local 呼叫的話,就是可以找 ConnectionFactory 裡面,有這東西,如果是遠端,大概要麻就是直接從那個 port 送進來,或者從 remote 那邊找進來了(網路上蠻多是走 jnp,不過 jnp 感覺好像又是另一門作業一.一")
                "ConnectionFactory" => {
                    "class-name" => "org.hornetq.jms.client.HornetQJMSConnectionFactory",
                    "value" => "HornetQConnectionFactory [serverLocator=ServerLocatorImpl [initialCo
nnectors=[TransportConfiguration(name=in-vm, factory=org-hornetq-core-remoting-impl-invm-InVMConnect
orFactory) ?server-id=0], discoveryGroupConfiguration=null], clientID=null, dupsOKBatchSize=1048576,
 transactionBatchSize=1048576, readOnly=true]"

JMS 像 default 起在 5445,也可以用 telnet 127.0.0.1 5445 驗證是否有在聽
            "java:jboss/exported" => {"jms" => {
                "class-name" => "javax.naming.Context",
                "children" => {"RemoteConnectionFactory" => {
                    "class-name" => "org.hornetq.jms.client.HornetQJMSConnectionFactory",
                    "value" => "HornetQConnectionFactory [serverLocator=ServerLocatorImpl [initialCo
nnectors=[TransportConfiguration(name=netty, factory=org-hornetq-core-remoting-impl-netty-NettyConne
ctorFactory) ?port=5445&host=127-0-0-1], discoveryGroupConfiguration=null], clientID=null, dupsOKBat
chSize=1048576, transactionBatchSize=1048576, readOnly=false]"
                }}
            }},


大概這樣,就可以跑一個簡單的 sample了。
話說,JMS 好像還有蠻多種作法(光找練習參考,就...總之每次建環境都覺得很無言啦...)
不過這個應該是最單純的,只靠設定用JBoss 內建的 JMS 來跑。


沒有留言: