第一章 搭建环境
如果机器上没有装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 |