從sample入手學習JMS

 

 

第一章  搭建環境

如果機器上沒有裝jdk,先安裝一下。我裝的是jdk1.6

sun官網下載jms-1_1-fr-apidocs.zip,解壓可見jms1.1目錄;

sun官網jms-1_0_2-upd-sampleprograms.zip,解壓到samples目錄;

jboss官網下載jboss-5.0.0.GA.zip,解壓可見jboss-5.0.0.GA目錄;

 

啓動jboss,如果能訪問到http://localhost:8080,說明jboss已經起來了。

進入cmd命令窗口,設置classpath

Set classpath=.;D:/Program Files/Java/jdk1.6.0/lib; D:/ebook/java/JMS/jms1.1/lib/javax.jms.jar;D:/ebook/java/JMS/jms1.1/lib/jms.jar;D:/software/jboss-5.0.0.GA/client/jnp-client.jar; D:/software/jboss-5.0.0.GA/client/jbossall-client.jar

jnp-client.jarjnp-client.jarjbossclient目錄下;javax.jms.jarjms.jarjms1.1lib目錄下。請根據自己的安裝路徑設置classpath

 

第二章  開始運行

進入samples目錄下,可以看到如下文件,先讀一下README

 

編譯所有的文件。

Javac *.java

 

運行SenderToQueue

Java  SenderToQueue SQ

 

1.  報錯,問題一:

Couldn't   build   an   initial   context   :   javax.naming.NoInitialContextException:   Cannot   instantiate   class:   org.jnp.interfaces.NamingContextFactory   [Root   exception   is   java.lang.ClassNotFoundException:   org.jnp.interfaces.NamingContextFactory]    

 

查看發現應該在SampleUtilities.java 的方法jndiLookup中加入一段代碼:

//增加InitialContext的綁定設置。

System.setProperty(Context.INITIAL_CONTEXT_FACTORY,

                        "org.jnp.interfaces.NamingContextFactory");

System.setProperty(Context.URL_PKG_PREFIXES,

                                "org.jboss.naming");

System.setProperty(Context.PROVIDER_URL, "localhost:1099");

 

jndiContext = new InitialContext();

 

2.  重新編譯運行,報錯,問題二:

javax.naming.NameNotFoundException: QueueConnectionFactory not bound

javax.naming.NameNotFoundException: TopicConnectionFactory not bound

 

查看jboss consolehttp://localhost:8080/jmx-console/ 發現jboss.messaging.connectionfactory jndi名字是ConnectoryFactory.所以把QueueConnectionFactoryTopicConnectionFactory的名字都改成ConnectoryFactory

connectionFactory

 

 

3.  重新編譯運行,報錯,問題三:

JNDI lookup failed: javax.naming.NameNotFoundException: SQ not bound

Connection problem: javax.naming.NameNotFoundException: SQ not bound

 

查看jboss consolejboss.messaging.destination,發現缺省情況下只有DLQExpiryQueue兩個Queue

 

Queue

 

如果要自定義Queue 或者Topic,可以destinations-service.xml文件中直接配置。該文件位於

jboss-5.0.0.GA/server/default/deploy/messaging/destinations-service.xml

如下是加一個testTopic的例子。

<!—Add the testTopic.-->

<mbean code="org.jboss.jms.server.destination.TopicService"

      name="jboss.messaging.destination:service=Topic,name=testTopic"

      xmbean-dd="xmdesc/Topic-xmbean.xml">

      <annotation>

@org.jboss.system.deployers.managed.ManagementObjectClass(code=org.jboss.jms.server.destination.TopicServiceMO)

</annotation>

      <depends optional-attribute-name="ServerPeer">

jboss.messaging:service=ServerPeer

</depends>

      <depends>jboss.messaging:service=PostOffice</depends>

   </mbean>

 

查看jboss consolejboss.messaging.destination,可以看到自己加的ABCDEcontrolQueuetestTopic都在列表中了。

all

 

點擊查看名爲DLQQueue,可以看到它的JNDI名字爲/queue/DLQ.jboss中所有的queueJNDI名字都是/queue/**, topicJNDI名字都是/topic/**,在代碼中寫對queue或者topicJNDI名字,就能找到啦。

 

detail 

至此,編譯運行成功。

 

第三章  解決問題參考的資料

1.  JNDI配置原理詳解

(轉自http://www.builder.com.cn/2007/1217/684114.shtml )

最近寫書,寫到JNDI,到處查資料,發現所有的中文資料都對JNDI解釋一通,配置代碼也是copy的,調了半天也沒調通,最後到SUN的網站參考了一下他的JNDI tutorial,終於基本上徹底明白了

和多數java服務一樣,SUNJNDI也只提供接口,使用JNDI只需要用到JNDI接口而不必關心具體實現:

private static Object jndiLookup() throws Exception {
  InitialContext ctx = new InitialContext();
  return ctx.lookup("java:comp/env/systemStartTime");
}

上述代碼在J2EE服務器環境下工作得很好,但是在main()中就會報一個NoInitialContextException,許多文章會說你創建InitialContext的時候還要傳一個Hashtable或者Properties,像這樣:

Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
env.put(Context.PROVIDER_URL,"t3://localhost:7001");
InitialContext ctx = new InitialContext(env);

這個在WebLogic環境下是對的,但是換到JBoss呢?再用JBoss的例子?

其實之所以有NoInitialContextException是因爲無法從System.properties中獲得必要的JNDI參數,在服務器環境下,服務器啓動時就把這些參數放到System.properties中了,於是直接new InitialContext()就搞定了,不要搞env那麼麻煩,搞了env你的代碼還無法移植,弄不好管理員設置服務器用的不是標準端口還照樣拋異常。

但是在單機環境下,可沒有JNDI服務在運行,那就手動啓動一個JNDI服務。我在JDK 5rt.jar中一共找到了4SUN自帶的JNDI實現:

LDAPCORBARMIDNS

4JNDI要正常運行還需要底層的相應服務。一般我們沒有LDAPCORBA服務器,也就無法啓動這兩種JNDI服務,DNS用於查域名的,以後再研究,唯一可以在main()中啓動的就是基於RMIJNDI服務。

現在我們就在main()中啓動基於RMIJNDI服務並且綁一個Date對象到JNDI上:

LocateRegistry.createRegistry(1099);
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL, "rmi://localhost:1099");
InitialContext ctx = new InitialContext();
class RemoteDate extends Date implements Remote {};
ctx.bind("java:comp/env/systemStartTime", new RemoteDate());
ctx.close();

注意,我直接把JNDI的相關參數放入了System.properties中,這樣,後面的代碼如果要查JNDI,直接new InitialContext()就可以了,否則,你又得寫Hashtable env = ...

RMI中綁JNDI的限制是,綁定的對象必須是Remote類型,所以就自己擴展一個。

其實JNDI還有兩個Context.SECURITY_PRINCIPALContext.SECURITY_CREDENTIAL,如果訪問JNDI需要用戶名和口令,這兩個也要提供,不過一般用不上。

在後面的代碼中查詢就簡單了:

InitialContext ctx = new InitialContext();
Date startTime = (Date) ctx.lookup("java:comp/env/systemStartTime");

 

2.  JNDI調用時,各種應用服務器InitialContext的寫法

(轉自http://www.blogjava.net/mashiguang/archive/2008/07/14/214758.html )

調用ejb,如果客戶端和ejb不在同一個jvm,就要設置InitialContext,不同的應用服務器InitialContext寫法也不同.

Context.INITIAL_CONTEXT_FACTORY:指定到目錄服務的連接工廠
Context.PROVIDER_URL:
目錄服務提供者URL.

 

//jboss:
Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"
Context.URL_PKG_PREFIXES, "org.jboss.naming"
Context.PROVIDER_URL, "localhost:1099"

 

//weblogic:

Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"

Context.PROVIDER_URL, "t3://localhost:7001"

 

//apusic(金蝶):

Context.INITIAL_CONTEXT_FACTORY, "com.apusic.jndi.InitialContextFactory"

Context.PROVIDER_URL, "rmi://localhost:6888"

 

//WebSphere:

Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"

Context.PROVIDER_URL, "iiop://localhost:900"

 

//J2EE  SDK(J2EE  RI):

Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"

Context.PROVIDER_URL, "iiop://127.0.0.1:1050"

 

//SilverStream:

Context.INITIAL_CONTEXT_FACTORY, "com.sssw.rt.jndi.AgInitCtxFactory"

Context.PROVIDER_URL, "sssw://localhost:80"

 

//OC4J:

Context.INITIAL_CONTEXT_FACTORY, "com.evermind.server.rmi.RMIInitialContextFactory"

Context.PROVIDER_URL, "ormi://127.0.0.1/"

 

//WAS5:

Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory"

Context.PROVIDER_URL, "iiop://localhost:2809"

 

常用JNDI服務提供者連接工廠:
Filesystem:  Com.sun.jndi.fscontext.FSContextFactory

或者com.sun.jndi.fscontext.RefFSContextFactory
LDAPv3:    Com.sun.jndi.ldap.LdapCtxFactory
NDS:       com.novell.naming.service.nds.NdsInitialContextFactory
NIS:       com.sun.jndi.nis.NISCtxFactory
RMI registry: com.sun.jndi.rmi.registry.RegistryContextFactory
IBM LDAP
服務提供者:   com.ibm.jndi.LDAPCtxFactory
BEA
名字服務提供者:    weblogic.jndi.WLInitialContextFactory
JBOSS
名字服務提供者:  org.jnp.interfaces.NamingContextFactory

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章