J2EE里的Session Bean,分无状态(Stateles)和有状态(Stateful)SessionBean,其实以术语意思来理解SessionBean中的那两种状态是很容易。在B/S开发模式当中Session技术应用得很广泛(对于它的应用就不多说了),而在SessionBean中也秉承着这种形式,只不过它与B/S模式开发当中不同的是,SessionBean中记录的状态是存放在应用服务器所提供的容器里,而B/S模式开发当中的Session存放在浏览器当中了。
当然J2EE中还有一个很大的概念是分布式,也即远程调用(当然不知道这么理解是不是正确的,姑且这么去理解吧)。在开发SessionBean时经常能看到所谓的本地接口和远程接口,需不需要本地接口和远程接口这就得根据你的系统架构来均衡了,如果你的客户端和你的EJB不在同一个服务器中运行的话那肯定得写远程接口,反之则可以只使用本地接口,当然客户端调用本地接口的效率比调用远程接口要高多了。
EJB3.0比起以前的版本开发起来轻便多了,其间的几行注释即可声明为什么Bean及什么接口,这好象是J2se5.0里的元数据注解语法有关。不过自己还没真正应用过J2se5.0中新的语法,我想熟悉它这也只是时间的问题了。
最后还是以代码+注释来进行整个SessionBean的demo进行解说吧。
StatelesSession Bean(无状态会话Bean)
服务端代码:
接口:
package com.foshanshop.ejb3;
//远程接口
public interface Operation {
public int Add(int a, int b);
}
package com.foshanshop.ejb3;
//本地接口
public interface LocalOperation extends Operation {
public int getResult();
}
实现类:(不知道EJB3.0里对于实现类的命名有没有规定,如以前的必须实现(接口名+Bean),有待验证...)
package com.foshanshop.ejb3.impl;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import com.foshanshop.ejb3.LocalOperation;
import com.foshanshop.ejb3.Operation;
@Stateless //声明为无状态会话Bean
@Remote({Operation.class})//声明远程接口,如需要更改远程接口的JNDI名则加上以下注释
//@RemoteBinding(jndiBinding="lzz/remotegood")
@Local({LocalOperation.class})//声明本地接口,如需要更改本地接口的JNDI名则加上以下注释
//@LocalBinding (jndiBinding="lzz/localgood")
public class OperationBean implements Operation, LocalOperation{
private int total = 0;
private int addresult = 0;
public int Add(int a, int b) {
addresult =a + b;
returnaddresult;
}
public int getResult() {
total +=addresult;
returntotal;
}
}
整个服务端的代码就已经写完了,剩下的就是将工程打包成*.jar文件部署到Jboss相应目录了。
客户端代码:
<%@ page contentType="text/html;charset=GBK"%>
<%@ page import="com.foshanshop.ejb3.Operation,com.foshanshop.ejb3.LocalOperation,
javax.naming.*, java.util.Properties"%>
<%
Properties props = new Properties();
props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url","localhost:1099");//如果客户端调用的是远程接口,则必须写成EJB所在服务器的IP,如:192.168.1.13:1099
props.setProperty("java.naming.factory.url.pkgs","org.jboss.naming");
InitialContext ctx = new InitialContext(props);
try {
Operation operation =(Operation)ctx.lookup("OperationBean/remote");");//此处的JNDI名如果服务器端没有声明成别的名则默认是(JavaBean名/远程接口),反之则写上声明的JNDI名,如以上声明的(lzz/remotegood)
out.println("通过远程接口调用EJB成功");
out.println("<br>(通过远程接口调用EJB)相加的结果是:"+operation.Add(1,1));
} catch (Exception e) {
out.println("<br>远程接口调用失败");
}
out.println("<br>==============================================");
try {
//通过本地接口调用EJB
LocalOperation A = (LocalOperation)ctx.lookup("OperationBean/local");//此处的JNDI名如果服务器端没有声明成别的名则默认是(JavaBean名/接口),反之则写上声明的JNDI名,如以上声明的(lzz/localgood)
out.println("<br>(通过本地接口调用EJB)调用A.Add()的结果是:"+A.Add(1,1));
out.println("<br>调用A.getResult()的结果是:"+A.getResult());
LocalOperation B = (LocalOperation)ctx.lookup("OperationBean/local");
out.println("<br>(通过本地接口调用EJB)调用B.Add()的结果是:"+B.Add(1,1));
out.println("<br>调用B.getResult()的结果是:<fontcolor=red>"+ B.getResult () +"</font>");
} catch (Exception e){
out.println("<br>本地接口调用失败");
}
%>
客户端部署到服务器里即可执行,这里还有一个很重要的问题,假如此jsp文件部署到的是和EJB同一个应用服务器中则可直接执行,如果是部署到其它应用服务器上如Tomcat,则必须将Jboss服务器所在目录下的client目录下的jar文件和部署到Jboss服务器的EJB服务端jar文件拷贝到此jsp文件所在目录的WEB-INF/lib目录下才可以执行,我想放入EJB服务端jar文件到客户端这里也就是代理设计模式的一个很好表现吧。
Stateful Session Beans(有状态会话Bean)
服务器端代码:
接口:
package com.foshanshop.ejb3;
import java.io.Serializable;
//这里与Stateles SessionBean(无状态会话Bean)不一样的是接口必须继承Serializable类
public interface MyAccount extends Serializable {
public intAdd(int a, int b);
public intgetResult() ;
}
实现类:
package com.foshanshop.ejb3.impl;
import javax.ejb.Remote;
import javax.ejb.Stateful;
import com.foshanshop.ejb3.MyAccount;
@Stateful//声明为有状态会话
@Remote(MyAccount.class)//声明为远程接口
//当然此处也可以声明本地接口或者更改JNDI名称,方法同上
public class MyAccountBean implements MyAccount{
private int total = 0;
private int addresult = 0;
public int Add(int a, int b) {
addresult =a + b;
returnaddresult;
}
public int getResult() {
total +=addresult;
returntotal;
}
}
打包部署跟StatelesSession Bean一样,此处省略...
客户端:
客户端的部署和代码都与Stateles SessionBean一样,需要注意的就是JNDI所在的服务器的路径和名称,具体代码省略...
开发SessionBean EJB就这么搞定,但还有一点要声明,就是关于SessionBean在服务器容器里的生命周期。无状态会话Bean呢,new一个实例只要程序执行完了这个实例的操作后,在服务器容器里它不一定会销毁这个实例,可能会给其它的客户端调用,这可能就会引起类中一些属性的值递增的情况;有状态会话Bean呢,客户端执行new一个实例的话它会在容器里记住此实例是那个客户端new的,所以客户端每执行一个new,那么容器里则会生成它对应的实例,如果你想调用容器里具体某个实例,那你就要在客户端保存那个客户端的对象,在JSP里通常的做法是用Session去保存客户端那个对象。。。