在EJB3规范中,Entity Bean被摒弃了,替代之的是实体与JPA(Java Persistence API,Java 数据持久化API)作为数据持久层解决方案。现在看看EJB3的规范:
图1
关于实体与JPA规范和hibernate之间的联系本文不care,本文的目的是研究SessionBean(会话企业bean),特别是无状态(stateless)SessionBean。
第一步
在myEclipse中新建一个EJB工程:
图2
JPA支持暂时不选,Maven也不启用,直接单击Finish。
创建一个名为HelloWorld的EJB SessionBean:
右键点击src——new 选择EJB3 SessionBean,看到如下界面
图3
注意Session Type选择Stateless(不保持客户机状态),自动创建Interface Remote(勾选后系统自动为我们创建HelloWorldRemote接口,暴露给客户机调用我们的远程方法),单击finish。
@Stateless public class HelloWorld implements HelloWorldRemote { }
我们看到系统给我们的函数名上面添加了注解。这种@annotation注解的方式替代了在EJB2规范中的xml配置方式,但同时也兼容XML配置方式。关于EJB还有几种@annotation注解我们以后再做讨论。
在HelloWorldRemote中我们写一个远程方法HelloEJB:
import javax.ejb.Remote; @Remote public interface HelloWorldRemote { public String HelloEJB(String name); }
control+s 一下然后发现 HelloWorld 这个实现类的类名被下滑花线标起来了,鼠标移上去,提示我们有未实现的接口方法,点第一个选项, myeclipse 直接帮我们创建该方法的模版代码,这也是先写接口 ( 当里面有很多很多方法的时候 ) 再写实现类的快速创建方法。
图4
本文的题目是创建EJB并通过JNDI进行引用,那么在我们的实现类中,必须绑定一个JNDI名,这里我们直接通过@Stateless(mappedName=”HelloEJB”)来绑定JNDI.
package com.getcoo.service; import javax.ejb.Stateless; @Stateless(mappedName="HelloEJB") public class HelloWorld implements HelloWorldRemote { public String HelloEJB(String name) { // TODO Auto-generated method stub return name+",你好,欢迎访问我的EJB。"; } }
接下来我们需要将此项目部署至jboss服务器,由于我这里myeclipse部署有点小问题,我们采用最笨拙的部署方式:
右键点击此项目,选择导出项目
图5
导出成Jar file
图6
选择以下导出路径,单击确定。
再打开jBoss控制台: localhost:8080
图7
展开图示的路径,我们发现helloEJB.jar还是没有出来,我再从右上角的add resource再添加一下(懒得找原因了),
图8
单击continue,OK 应该是部署好了
图9
图10
等status变为Success。
第二步:
还是在这个工程下创建一个test类(如果另建一个普通java工程,需要把上面的两个java文件拷贝过去,或者jar包拷过去当做lib,不然无法import):
/** * */ package com.getcoo.client; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import com.getcoo.service.HelloWorldRemote; /** * @author 墨半成霜 * */ public class HelloEJBTest { public void test() throws NamingException{ Context jbossCtx = getJBossInitialContext(); HelloWorldRemote myEJB =(HelloWorldRemote)jbossCtx.lookup("HelloEJB"); System.out.println("成功获得对远程EJB实例的引用,该引用实例为:"+myEJB); System.out.println(myEJB.HelloEJB("墨半成霜")); } private Context getJBossInitialContext() { final String INIT_FACTORY="org.jnp.interfaces.NamingContextFactory"; final String SERVER_URL="localhost:1099"; Context ctx=null; try{ Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY,INIT_FACTORY); props.put(Context.PROVIDER_URL, SERVER_URL); ctx= new InitialContext(props); } catch (NamingException ne){ System.err.println("不能连接JBoss Server 在:"+SERVER_URL); ne.printStackTrace(); } return ctx; } public static void main(String[] args) throws Exception { HelloEJBTest client= new HelloEJBTest(); client.test(); } }
run一下:
不能连接JBoss Server 在:localhost:1099 javax.naming.NoInitialContextException: Cannot instantiate class: org.jnp.interfaces.NamingContextFactory [Root exception is java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory] at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:657) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288) at javax.naming.InitialContext.init(InitialContext.java:223) at javax.naming.InitialContext.<init>(InitialContext.java:197) at com.getcoo.client.HelloEJBTest.getJBossInitialContext(HelloEJBTest.java:38) at com.getcoo.client.HelloEJBTest.test(HelloEJBTest.java:22) at com.getcoo.client.HelloEJBTest.main(HelloEJBTest.java:50) Caused by: java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory at java.net.URLClassLoader$1.run(URLClassLoader.java:200) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:247) at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:46) at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:654) ... 6 more Exception in thread "main" java.lang.NullPointerException at com.getcoo.client.HelloEJBTest.test(HelloEJBTest.java:23) at com.getcoo.client.HelloEJBTest.main(HelloEJBTest.java:50)
Why?我仔细检查了一下,我这里没有错,如果被这一大堆错误吓懵了 立马去找错误的话,不是一个好程序员,我们要看什么呢?要找Root exception,对根源异常,往往这是问题关键。
root exception显示:
Cannot instantiate class: org.jnp.interfaces.NamingContextFactory [Root exception is java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory]
多么清楚的异常,org.jnp.interfaces.NamingContextFactory这个类系统没找到。那么说我命我们引用了这个类,但是没在添加相关的lib。
这个类是jBoss的JNDI 命名上下文工厂类,我们不管了,直接把上个例子中添加的jBoss lib添加进来:
图11
再run一次:
成功获得对远程EJB实例的引用,该引用实例为:Proxy to jboss.j2ee:jar=helloEJB.jar,name=HelloWorld,service=EJB3 implementing [interface com.getcoo.service.HelloWorldRemote] 墨半成霜,你好,欢迎访问我的EJB。