每次学习一些新的东西都是从Hello World开始,这里感叹一下。本来认为Hello World这样的东西应该不必要再写,只想发两句牢骚,转几个链接了事,但接触下来,发现网上的Hello World因为转载太多,造成基本上都是不能用的版本.或多或少存在这样那样的问题,让一个初学者去调试错误是好事,也是坏事,好事是可以锻炼一下,坏事是容易打消积极性,呵呵。这里给出一个Hello World的例子和一些疑问.
首先是Hello World的代码,很简单就几个接口
1,远程接口
package eg;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface Hello extends EJBObject {
public String hello() throws RemoteException;
}
2,企业Bean
package eg;
import java.rmi.RemoteException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloBean implements SessionBean {
private SessionContext ctx;
public void ejbActivate() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
public void ejbPassivate() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
public void ejbCreate() throws javax.ejb.CreateException {
}
public void ejbRemove() throws EJBException, RemoteException {
// TODO Auto-generated method stub
}
public void setSessionContext(SessionContext ctx) throws EJBException,
RemoteException {
this.ctx = ctx;
}
public String hello() {
System.out.println("hello");
return "Hello World";
}
}
3,Home接口
package eg;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface HelloHome extends EJBHome {
Hello create() throws RemoteException,CreateException;
}
4,用来调用的Client类
package eg;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public class HelloClient {
public static void main(String[] args) throws Exception {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
env.put(Context.PROVIDER_URL, "localhost:1099");
env.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
Context ctx = new InitialContext(env);
Object obj = ctx.lookup("Hello");
HelloHome home = (HelloHome) PortableRemoteObject.narrow(obj,
HelloHome.class);
Hello hello = home.create();
System.out.println(hello.hello());
hello.remove();
}
}
ejb-jar.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<description>this is ejb helloworld</description>
<display-name>HelloBean</display-name>
<enterprise-beans>
<session>
<display-name>Hello</display-name>
<ejb-name>Hello</ejb-name>
<home>eg.HelloHome</home>
<remote>eg.Hello</remote>
<!--
<local-home>eg.HelloLocalHome</local-home>
<local>eg.HelloLocal</local>
-->
<ejb-class>eg.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar> 上边代码下载链接
http://www.blogjava.net/Files/dreamstone/ejb.rar疑问一:细心的人会发现我的ejb-jar.xml中注释掉了两行,这两行对应两个本地接口
package eg;
import javax.ejb.EJBLocalObject;
public interface HelloLocal extends EJBLocalObject {
public String hello();
}
package eg;
import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;
public interface HelloLocalHome extends EJBLocalHome {
HelloLocal create() throws CreateException;
}
这两个接口是用来本地调用的,这个解释明白它的意思,但还是不知道如何才能实现这个本地调用,了解的人给个提示,如何才能在代码中模拟出使用到这两个接口的情况。或者说模拟出使用本地接口和远程接口的区别?
疑问二:为什么企业Bean类不实现组建接口(既不实现远程接口也不实现本地接口),毕竟组建接口定义了企业Bean所有的业务方法,如果实现了,可以保证编译期Check
答案:这个答案是<<精通Ejb>>一书中给出的解释:
理由一:组件接口继承于Sun定义的标准接口,比如javax.ejb.EJBObject和javax.ejb.EJBLocalObject。这些超级接口为客户定义了其它方法。因此如果企业Bean类实现组件接口,则企业Bean类将需要为这些方法提供空的实现,显然,在企业Bean类中不需要这些方法
理由二:
假定企业Bean (A)需要调用其它企业Bean(B)的方法,并且,如果需要传递当前企业Bean(A)的引用给B的方法(类似于Java中的this参数)。在Ejb中,如何传递和处理这种情形?
请记住,所有的Ejb客户都是调用Ejb对象而不是企业Bean类实例本身,因此如果A调用B,开发者必须将A的Ejb对象引用(而不是对A的引用)传递给B,B将操作A的EJB对象,而不是A中企业Bean实例本身,对于A而言,B是它的客户,同所有的EJB客户一样,必须通过EJB对象调用企业Bean类实例。
而且如果企业Bean类实现了EJB组件的远程接口将存在潜在的危险,开发者可能不小心将企业Bean类的实例本身的引用传递,而不是EJB对象的引用,犹豫企业Bean类同EJB对象实现了同一接口,似的开发者能够使用this参数,而实现对企业Bean本身的引用。这太不可思议了。
看完这段解释,朦胧的懂了为什么不这么做,但是对这么作带来的后果还是不是很清楚,有经验的给说说.谢谢.
另外部署不说了,看这里吧
http://www.uml.org.cn/j2ee/200702141.asp如果调用Client的时候抛出这个异常:
Exception in thread "main" 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:247)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.<init>(InitialContext.java:197)
at eg.HelloClient.main(HelloClient.java:17)
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:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:242)
at com.sun.naming.internal.VersionHelper12.loadClass(VersionHelper12.java:42)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:654)
... 4 more
把Jboss Client目录下的一些类库加进来就好了
最后提供一个简单的做法:
Eclipse+Myeclipse
新建EJB工程-->新建SessionBean,名字叫HelloBean ,更改里边的业务方法
然后选择工程的属性-->Myeclipse xDoclet -->add Standard -->standard EJB -->确定
右键工程-->Myeclipse-->run xDoclet,看看是不是和上边的差不多,什么都有了,不过他的结构更好一点,借助工具能更快捷的完成任务。不过建议初学者还是自己手动来比较好。
借助Eclipse+Myeclipse 部署调试也会变的方便.