第一章 搭建環境
如果機器上沒有裝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.jar和jnp-client.jar在jboss的client目錄下;javax.jms.jar和jms.jar在jms1.1的lib目錄下。請根據自己的安裝路徑設置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 console,http://localhost:8080/jmx-console/ 發現jboss.messaging.connectionfactory 的jndi名字是ConnectoryFactory.所以把QueueConnectionFactory和TopicConnectionFactory的名字都改成ConnectoryFactory。
3. 重新編譯運行,報錯,問題三:
JNDI lookup failed: javax.naming.NameNotFoundException: SQ not bound Connection problem: javax.naming.NameNotFoundException: SQ not bound |
查看jboss console的jboss.messaging.destination,發現缺省情況下只有DLQ和ExpiryQueue兩個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 console的jboss.messaging.destination,可以看到自己加的A、B、C、D、E、controlQueue和testTopic都在列表中了。
點擊查看名爲DLQ的Queue,可以看到它的JNDI名字爲/queue/DLQ.在jboss中所有的queue的JNDI名字都是/queue/**, topic的JNDI名字都是/topic/**,在代碼中寫對queue或者topic的JNDI名字,就能找到啦。
至此,編譯運行成功。
第三章 解決問題參考的資料
1. JNDI配置原理詳解
(轉自http://www.builder.com.cn/2007/1217/684114.shtml )
最近寫書,寫到JNDI,到處查資料,發現所有的中文資料都對JNDI解釋一通,配置代碼也是copy的,調了半天也沒調通,最後到SUN的網站參考了一下他的JNDI tutorial,終於基本上徹底明白了 和多數java服務一樣,SUN對JNDI也只提供接口,使用JNDI只需要用到JNDI接口而不必關心具體實現: private static Object jndiLookup() throws Exception { 上述代碼在J2EE服務器環境下工作得很好,但是在main()中就會報一個NoInitialContextException,許多文章會說你創建InitialContext的時候還要傳一個Hashtable或者Properties,像這樣: Hashtable env = new Hashtable(); 這個在WebLogic環境下是對的,但是換到JBoss呢?再用JBoss的例子? 其實之所以有NoInitialContextException是因爲無法從System.properties中獲得必要的JNDI參數,在服務器環境下,服務器啓動時就把這些參數放到System.properties中了,於是直接new InitialContext()就搞定了,不要搞env那麼麻煩,搞了env你的代碼還無法移植,弄不好管理員設置服務器用的不是標準端口還照樣拋異常。 但是在單機環境下,可沒有JNDI服務在運行,那就手動啓動一個JNDI服務。我在JDK 5的rt.jar中一共找到了4種SUN自帶的JNDI實現: LDAP,CORBA,RMI,DNS。 這4種JNDI要正常運行還需要底層的相應服務。一般我們沒有LDAP或CORBA服務器,也就無法啓動這兩種JNDI服務,DNS用於查域名的,以後再研究,唯一可以在main()中啓動的就是基於RMI的JNDI服務。 現在我們就在main()中啓動基於RMI的JNDI服務並且綁一個Date對象到JNDI上: LocateRegistry.createRegistry(1099); 注意,我直接把JNDI的相關參數放入了System.properties中,這樣,後面的代碼如果要查JNDI,直接new InitialContext()就可以了,否則,你又得寫Hashtable env = ... 在RMI中綁JNDI的限制是,綁定的對象必須是Remote類型,所以就自己擴展一個。 其實JNDI還有兩個Context.SECURITY_PRINCIPAL和Context.SECURITY_CREDENTIAL,如果訪問JNDI需要用戶名和口令,這兩個也要提供,不過一般用不上。 在後面的代碼中查詢就簡單了: InitialContext ctx = new InitialContext(); |
2. JNDI調用時,各種應用服務器InitialContext的寫法
(轉自http://www.blogjava.net/mashiguang/archive/2008/07/14/214758.html )
調用ejb時,如果客戶端和ejb不在同一個jvm,就要設置InitialContext,不同的應用服務器InitialContext寫法也不同. Context.INITIAL_CONTEXT_FACTORY:指定到目錄服務的連接工廠
//jboss:
//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服務提供者連接工廠: 或者com.sun.jndi.fscontext.RefFSContextFactory |