无标题文档 用 WSAD5.0和SQLServer2K采用Meet-in-Middle模式开发 CMP实体Bean及其完整客户端
(下篇:客户端的开发和性能优化)
abnerchai( 柴政 ) 2004 年 6 月
接上篇:
14 、下面我们编写一个 SessionBean 来测试我们的 CMP 实体 Bean 。我们的通常做法是用 SessionBean 来封装 CMP 实体 Bean ,然后再在 JavaBean 和 Servlets 及 jsp 中引用该 SessionBean 。这样使得 CMP 实体 Bean 对用户来说是不可见的。创建 SessionBean 的过程如下:
首先,接着上面的步骤,在 j2ee 视图中的 ejbModule 下建一个包,并命名为: com.employee.session
然后,再在此包上点右键 -> 新建 -> 其它如下图所示:
然后在弹出的框中选择 EJB-> 企业 Bean ,如下图所示,并选择“下一步”
进入如下图所示,选择好后,单击“下一步”
进入如下图所示画面:
在上图中,选择“会话 bean ”,并在 Bean 名中,输入: EmployeeSession ,并把缺省包选择为: com.employee.session, 然后点击下一步。进入如下图所示:
这里无须变动,直接点击“完成”。
这样,便创建了一个 StateLess SessionBean ,它包括三个文件:
Remote 接口: EmployeeSession.java
Home 接口: EmployeeSessionHome.java
Bean 本身: EmployeeSessionBean.java
下面我们来修改 SessionBean ,使之对 CMP 实体 BEAN 进行包装。
在 j2ee 视图中,双击 com.employee.session 包下面的 EmployeeSessionBean.java 文件,打开它编辑,在类中增加方法,增加后的 EmployeeSessionBean.java 文件内容如下所示:
package com.employee.session;
import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import javax.ejb.CreateException;
import javax.ejb.FinderException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import com.employee.com.Employee;
import com.employee.com.EmployeeHome;
import com.employee.com.EmployeeKey;
/**
* Bean implementation class for Enterprise Bean: EmployeeSession
*/
public class EmployeeSessionBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
/**
* getSessionContext
*/
public javax.ejb.SessionContext getSessionContext() {
return mySessionCtx;
}
/**
* setSessionContext
*/
public void setSessionContext(javax.ejb.SessionContext ctx) {
mySessionCtx = ctx;
}
/**
* ejbCreate
*/
public void ejbCreate() throws javax.ejb.CreateException {
}
/**
* ejbActivate
*/
public void ejbActivate() {
}
/**
* ejbPassivate
*/
public void ejbPassivate() {
}
/**
* ejbRemove
*/
public void ejbRemove() {
}
/**
* 私有方法,获得实体Bean的Home接口
* @return 返回实体Bean的Home接口对象
*/
private EmployeeHome getEmployeeHome(){
InitialContext initialContext = null ;
EmployeeHome employeeHome = null ;
try {
initialContext = new InitialContext();
Object employeeHomeObject = initialContext.lookup( "ejb/com/employee/com/EmployeeHome" );
employeeHome = (EmployeeHome)PortableRemoteObject.narrow(employeeHomeObject,EmployeeHome. class );
} catch (NamingException e){
System.err.println( "CaughtException:" +e.toString());
employeeHome = null ;
e.printStackTrace();
} finally {
if (initialContext!= null )
try {
initialContext.close();
} catch (NamingException e) {
}
}
return employeeHome;
}
/**
* 私有方法:获得一个对应ID的实体Bean实体对象,如果没有找到,则用
* 给定的ID创建一个实体Bean对象
* @param id:给定要查找的对象的id
* @return 返回给定ID的一个对应的实体对象
*/
private Employee getEmployee( int id){
Employee employee = null ;
EmployeeHome employeeHome = this .getEmployeeHome();
try {
try {
if (employeeHome!= null ){
employee = employeeHome.findByPrimaryKey( new EmployeeKey(id));
}
} catch (FinderException e) {
System.out.println( "Can not find a Employee with gived id,So try to create one." );
employee = employeeHome.create(id, null , null );
}
} catch (Exception e) {
System.err.println( "CaughtException:" +e.toString());
employee = null ;
e.printStackTrace();
} finally {
employeeHome = null ;
}
return employee;
}
/**
* 远程方法:用给定的信息生成一个实体Bean对象记录。
* @param id:给定需要创建对象的id
* @param name:给定要创建对象的name
* @param email:给定要创建对象的email
* @return 返回成功创建对象的id
*/
public int createOneEmployee( int id,String name,String email){
EmployeeHome employeeHome = this .getEmployeeHome();
try {
if (employeeHome!= null ){
employeeHome.create(id,name,email);
}
} catch (RemoteException e) {
System.err.println( "CaughtException:" +e.toString());
e.printStackTrace();
} catch (CreateException e) {
System.err.println( "CaughtException:" +e.toString());
e.printStackTrace();
} finally {
employeeHome = null ;
}
return id;
}
/**
* 远程方法:返回给定id对应对象的name
* @param id:给定的id
* @return 返回对应id对象的name字符串
*/
public String getNameById( int id){
String name = null ;
Employee employee = null ;
employee = this .getEmployee(id);
if (employee!= null ) try {
name = employee.getName();
} catch (RemoteException e) {
System.err.println( "Can not get Name by given id!" );
employee = null ;
e.printStackTrace();
}
return name;
}
/**
* 远程方法:返回给定id对应对象的email
* @param id:给定的id
* @return 返回对应id对象的email字符串
*/
public String getEmailById( int id){
String email = null ;
Employee employee = null ;
employee = this .getEmployee(id);
if (employee!= null ) try {
email = employee.getEmail();
} catch (RemoteException e) {
System.err.println( "Can not get Email by given id!" );
employee = null ;
e.printStackTrace();
}
return email;
}
/**
* 远程方法:给定一个id和name,将该id对应的name设定为给定的name
* @param id:给定的id
* @param name,新的name
* @return 返回设定对象的id
*
*/
public int setNameById( int id,String name){
Employee employee = null ;
employee = this .getEmployee(id);
try {
employee.setName(name);
} catch (RemoteException e) {
System.err.println( "Can not set name by given id!" );
employee = null ;
e.printStackTrace();
}
return id;
}
/**
* 远程方法:给定一个id和email,将该id对应的email设定为给定的email
* @param id:给定的id
* @param name,新的email
* @return 返回设定对象的id
*
*/
public int setEmailById( int id,String email){
Employee employee = null ;
employee = this .getEmployee(id);
try {
employee.setEmail(email);
} catch (RemoteException e) {
System.err.println( "Can not set email by given id!" );
employee = null ;
e.printStackTrace();
}
return id;
}
/**
* 远程方法:查找所有的实体Bean对象
* @return 返回查找到的所有的实体Bean对象的id的集合,是Integer保存的
*/
public Collection findAllEmployees(){
Vector allId = new Vector();
EmployeeHome employeeHome = this .getEmployeeHome();
try {
if (employeeHome!= null ){
Collection allEmployee = employeeHome.findAllEmployees();
Iterator iterator = allEmployee.iterator();
while (iterator.hasNext()){
Employee employee = (Employee) iterator.next();
allId.add( new Integer(employee.getId()));
} //end while
} //end if
} catch (Exception e) {
System.err.println( "FindAllEmployees Caught Exception!" );
employeeHome = null ;
e.printStackTrace();
}
return allId;
}
/**
* 远程方法:给出name查找所有对应的实体Bean对象
* @param name:给定的name
* @return 返回查找到的所有的实体Bean对象的id的集合,是Integer保存的
*/
public Collection findAllEmployeesByName(String name){
Vector allId = new Vector();
EmployeeHome employeeHome = this .getEmployeeHome();
try {
if (employeeHome!= null ){
Collection allEmployee = employeeHome.findByName(name);
Iterator iterator = allEmployee.iterator();
while (iterator.hasNext()){
Employee employee = (Employee) iterator.next();
allId.add( new Integer(employee.getId()));
} //end while
} //end if
} catch (Exception e) {
System.err.println( "findAllEmployeesByName Caught Exception!" );
employeeHome = null ;
e.printStackTrace();
}
return allId;
}
/**
* 远程方法:给出email查找所有对应的实体Bean对象
* @param email:给定的email
* @return 返回查找到的所有的实体Bean对象的id的集合,是Integer保存的
*/
public Collection findAllEmployeesByEmail(String email){
Vector allId = new Vector();
EmployeeHome employeeHome = this .getEmployeeHome();
try {
if (employeeHome!= null ){
Collection allEmployee = employeeHome.findByEmail(email);
Iterator iterator = allEmployee.iterator();
while (iterator.hasNext()){
Employee employee = (Employee) iterator.next();
allId.add( new Integer(employee.getId()));
} //end while
} //end if
} catch (Exception e) {
System.err.println( "findAllEmployeesByEmail Caught Exception!" );
employeeHome = null ;
e.printStackTrace();
}
return allId;
}
}
然后把增加的一些 public 方法提升至远程方法,把下列方法提升至远程方法:
createOneEmployee ()、 getNameById 、 getEmailById 、 setNameById 、 setEmailById 、 findAllEmployees 、 findAllEmployeesByName 、 findAllEmployeesByEmail ,提升后,屏幕左下角的轮廓视图如下图所示:
紧接着,对此 SessionBean 进行生成部署代码,在 j2ee 视图中的层次结构下,选中 EmployeeSession ,点右键,生成部署代码,如下图所示:
注意,我们在上面的 SessionBean 中访问实体 Bean ,是通过查找实体 Bean 的实际的 jndi 名字来获得对实体 Bean 的引用的。同时,实体 Bean 引用数据库连接池也是使用数据库连接的 jndi 名字来引用数据库连接的。
然而,在许多时候,我们可以使用“资源映射”来访问实体 Bean ,也就是说: SessionBean 在访问实体 Bean 的时候,采用 lookup(“java:comp/env/Employee”) 来查找实体 Bean ,而这里的查找是采用 j2ee 推荐的标准名字空间,这里的 Employee 是一个别名,在这里它对应着我们的 Employee 实体 Bean ,这个对映关系由资源映射符来确定,也就是说资源映射符定义了这里的别名 Employee 和实体 Bean 的 Employee 的 jndi 之间的对应关系。这种使用方式的优点是,在程序中可以写死调用的别名,具体实际调用的是哪一个 EJB 由布署时在资源映射符中定义。
如果你接受以上用法会给你的 EJB 开发和部署带来好处,那么请继续看下去如何做来定义这些资源引用,如果你不接受这个观点,你认为在程序中将 EJB 的 jndi 名字写死,那么请跳过下一段,直接进入 18 小节阅读。
好,下面我们来看如何修改我们的 SessionBean ,使之采用资源映射的方式来访问我们的实体 Bean 。第一步,修改代码,打开 EmployeeSessionBean.java 文件,找到其中的:
private EmployeeHome getEmployeeHome() 方法,把它修改成如下所示:
private EmployeeHome getEmployeeHome(){
InitialContext initialContext = null ;
EmployeeHome employeeHome = null ;
try {
initialContext = new InitialContext();
//Object employeeHomeObject = initialContext.lookup("ejb/com/employee/entity/EmployeeHome");
//采用资源引用,不直接采用jndi查找
Object employeeHomeObject = initialContext.lookup( "java:comp/env/EmployeeRef" );
employeeHome = (EmployeeHome)PortableRemoteObject.narrow(employeeHomeObject,EmployeeHome. class );
} catch (NamingException e){
System.err.println( "CaughtException:" +e.toString());
employeeHome = null ;
e.printStackTrace();
} finally {
if (initialContext!= null )
try {
initialContext.close();
} catch (NamingException e) {
}
}
return employeeHome;
}
在上面的代码中,我们只修改了一句,把原来采用 jndi 来查找实体 Bean 的方法改为了采用资源引用的方式,在这里,我们用 EmployeeRef 这个别名来引用实体 Bean 。
下面我们来修改部署描述符文件,增加资源引用部分。在 WSAD 左边 j2ee 视图中的 j2ee 层次结构视图中,打开 EJB 模块下的会话 Bean ,双击其下的 EmployeeSession ,在右边的视图中打开其部署描述符文件,选择“引用”页面,如下图所示:
选择 EmployeeSession ,然后单击其下方的“添加”按钮,如下图所示:
选中“ EJB ”引用,点击“下一步”,如下图所示:
在上图中,选择“当前 EJB 项目中的企业 bean ”,然后在列表中选择中“ Employee ”,并把系统在“名称”中填入的 ejb/Employee 修改为“ EmployeeRef ”,这是我们在程序中引用的别名。然后点“下一步”,并在下一步中点“完成”。重新回到了部署描述符文件中。如下图所示:系统自动填写完毕。
保存并退出部署描述符修写。
重新生成 EmployeeSession 的部署代码,并重新编译 EJB 。
然后,我们可以像第 11 步中那样启动通用测试客户机来测试我们的的 SessionBean 。在 J2ee 视图中的 j2ee 层次结构中,选中 EmployeeSession ,点右键,在服务器上运行即可。
性能优化,在这一小节中,我们来看看如何优化 SessionBean 来调用实体 Bean 的性能,由于 SessionBean 通过远程接口 lookup 实体 Bean ,所以大部分时间均发在 lookup 上面了。为了优化 SessionBean 调用实体 Bean 的性能,我们在这里给出一个参考方案即采用“重用 Home 句柄”技术。也就是将需要在 SessionBean 中调用的实体 Bean 的 home 句柄用缓存保存起来,为了达到这个目地,我们需引入单根模式来设计一个 EjbHomeCacheHelper 类。
在 j2ee 视图中,像前面编写 SessionBean 一样,新建一个包并命名为: com.ejbhome.helper ,然后再在此包在新建一个类,并命名为: EjbHomeCacheHelper ,其全部代码如下:(其代码是自解释的)
package com.ejbhome.helper;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import com.employee.entity.EmployeeHome;
/**
* @author abnerchai
* 本方法采用单根模式来存储所有的实体Bean的Home句柄,这样系统中有
* 多少个实体Bean,那么在本对象中就存储了多少个Home对象柄,在本对象
* 第一次初始化时就将所有的实体Bean的Home句柄保存起来放在内存中,下一次其它的
* SessionBean欲调用实体BEAN时,只需从内存中获得即可,这样可以大大提高调用的
* 速度和性能。
*/
public class EjbHomeCacheHelper {
//定义所有的对实体Bean的引用名字在这里,有几个实体Bean,这里就定义几个引用常量
private static final String EmployeeRef = "EmployeeRef" ;
//采用单根模式
private static EjbHomeCacheHelper ejbHomeCache = null ;
//定义保存所有Home句柄引用的表
private Hashtable ejbHomeTable = new Hashtable();
//采用单根模式,将构造器设置为私有的
private EjbHomeCacheHelper(){
}
//返回表
private Hashtable getejbHomeTable(){
return ejbHomeTable;
}
private synchronized static EjbHomeCacheHelper getInstance(){
if (ejbHomeCache == null ){ //第一次运行为空,便构建一个,以便所有的共享
ejbHomeCache = new EjbHomeCacheHelper();
//构建实体BEAN柄集合
ejbHomeCache.buildHomeHandleCache();
}
return ejbHomeCache;
}
//构建出所有的实体Bean的Home句柄的集合并保存起来
private void buildHomeHandleCache(){
Context ctx = null ;
Object homeObject = null ;
EmployeeHome employeeHome = null ;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory" );
try {
ctx = new InitialContext(env);
homeObject = ctx.lookup( "java:comp/env/EmployeeRef" );
employeeHome = (EmployeeHome)PortableRemoteObject.narrow(homeObject,EmployeeHome. class );
getejbHomeTable().put(EmployeeRef,employeeHome);
//可以在这里加入其它的对实体Bean的引用并把它放入cache表中,需要引用几个实体Bean,
//这里就加上几个查找并put的方法
} catch (Exception e){
e.printStackTrace();
} finally {
if (ctx!= null ){
try {
ctx.close();
} catch (NamingException e1) {
e1.printStackTrace();
}
} //end if
} //end finally
} //end buildHomeHandleCache
//以下所有的方法对外开放,用于外部引用实体Bean时获得实体Bean的Home句柄
//有几个实体Bean,这里就定义几个方法
public static EmployeeHome getEmployeeHome(){
return (EmployeeHome)getInstance().getejbHomeTable().get(EmployeeRef);
}
} //end class
然后,我们就采用这个工具类来调用我们的实体 Bean 了,在 EmployeeSessionBean.java 文件中新增一个方法:名字为: getEmployeeHomeFromCache() ,其内容如下:
/**
* 私有方法,通过实体Bean缓存来获得EmployeeHome接口
* 可以大大提高性能
* @return 返回实体Bean的Home接口对象
*/
private EmployeeHome getEmployeeHomeFromCache(){
return EjbHomeCacheHelper.getEmployeeHome();
}
即可。在需要调用实体 Bean获得Home的地方,采用此方法替换即可。
下面我们来开发一个 JavaBean 和一个 JSP 页面来调用我们的 EJB ,过程如下:
在 J2ee 视图中,点菜单中的“文件” -> “新建” -> “项目”,如下图所示:
选择左边的 WEB ,选择中右边的“动态 Web 项目” , 点下一步。如下图所示:
在项目名中填写 HelloWorldWebProject ,并选择中“配置高级选项”然后点“下一步”即可如下图所示:
按上图中所示选择 EAR 项目为己有的 HelloWorldEARProject ,上下文根不变即可。然后点“下一步”,如下图所示:
在上图中什么也不选择,直接点击“完成”,在弹出的两个如下图所示的对话框中,选择“确定修改服务器配置”和“不切换到 WEB 视图”即可。
然后,在 WSAD 左边 J2ee 视图中出现了如下图所示的情况:
在上图中,在当前 EAR 项目中新建了一个 WEBProject 项目,这个 WEB 项目下面包括两部分:一个是 Java Source ( Java 资源),另一个是 Web Content 。前者用于管理和存放 JavaBean 及 Servlets ,后者用于存放和管理 JSP 及 HTML 等页面文件。
接着在上图中,右键选中“ java 资源”,点击右键菜单中,选择“新建” -> “包”如下图所示:
弹出如下图所示对话框:
在上图中名称栏中输入: ”com.employee.bean” 包名。点完成即可。然后再在左边的 J2ee 视图中选择刚建好的包,点右键,“新建” -> “类”如下图所示:
弹出如下图所示对话框:
在此图中,名称一栏中填入“ EmployeeJavaBean ”做为我们的 JavaBean 名字,然后点“完成”即可打开编辑这个 JavaBean 的代码窗口。
此时,右键点击 J2ee 视图中的 EmployeeWebProject ,选择“属性”,然后在弹出的对话框中左边选择“项目引用”,如下图所示:
右边请选择中 HelloWorldEJBProject ,。接着,选择这个图左边的“ Java 构建路径”,在右边出来的窗口中选择中“项目”一页,如下图所示:
在上图中选中“ HelloWorldEJBProject ”,然后点确定。这样一来,我们的 WEB 项目就可以调用 EJB 了。下面我们来编写 javaBean 我们这个 EmployeeJavaBean 是用来提供给 JSP 页面来调用 EJB 的。编写后的代码如下所示:
package com.employee.bean;
import java.rmi.RemoteException;
import java.util.Hashtable;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.servlet.http.HttpServletRequest;
import com.employee.session.EmployeeSessionHome;
import com.employee.session.EmployeeSession;
public class EmployeeJavaBean {
private HttpServletRequest _request = null ;
public void init(HttpServletRequest req){
this ._request = req;
}
private EmployeeSession getEmployeeSession(){
Context ctx = null ;
Object homeObject = null ;
EmployeeSessionHome employeeSessionHome = null ;
EmployeeSession employeeSession = null ;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory" );
try {
ctx = new InitialContext(env);
homeObject = ctx.lookup( "ejb/com/employee/session/EmployeeSessionHome" );
employeeSessionHome = (EmployeeSessionHome)PortableRemoteObject.narrow(homeObject,EmployeeSessionHome. class );
employeeSession = employeeSessionHome.create();
} catch (Exception e){
e.printStackTrace();
} finally {
if (ctx!= null ){
try {
ctx.close();
} catch (NamingException e1) {
e1.printStackTrace();
}
} //end if
} //end finally
return employeeSession;
}
public String getNameByEmployeeID(){
String id = this ._request.getParameter( "ID" );
if (id== null ) return null ;
int int_id = Integer.parseInt(id);
String name = null ;
try {
name = this .getEmployeeSession().getNameById(int_id);
} catch (RemoteException e) {
e.printStackTrace();
}
return name;
}
}
注意,为了演示,我在 JavaBean 中只编写了一个方法,该方法来调用 SessionBean 中的方法。
下面我们新建一个 JSP 文件,来调用我们的 JavaBean ,过程如下:
在 J2ee 视图中,右键选中 WebContent , ” 新建 ”-> “ JSP 文件”如下图所示:
在弹出的对话框中如下图:
填入文件名为 index.jsp 。然后点击完成。进入编辑 JSP 页面。
修改后的 JSP 文件代码如下所示:
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" >
< HTML >< HEAD >
<%@ page language = "java" contentType = "text/html; charset=GBK" pageEncoding = "GBK" %>
< jsp:useBean id = "employeeJB" class = "com.employee.bean.EmployeeJavaBean" scope = "page" ></ jsp:useBean >
< META http-equiv = "Content-Type" content = "text/html; charset=GBK" >
< META name = "GENERATOR" content = "IBM WebSphere Studio" >
< TITLE > index.jsp </ TITLE >
</ HEAD >
< BODY >
<%
String name = null ;
if (request.getMethod().equalsIgnoreCase( "post" )){
employeeJB.init(request);
name = employeeJB.getNameByEmployeeID();
}
%>
< p > 请输入你要查找的ID: </ p >
< form name = "base" method = "POST" action = "index.jsp" >
< input type = "text" value = "" name = "ID" >
< input type = "submit" value = "查找!" >
</ form >
<%
if (name!= null ){
out.println( "<p>你查找的名字是:" +name+ "</p>" );
}
%>
</ BODY >
</ HTML >
测试: 启动服务器,在 IE地址栏中输入: http://localhost:9080/HelloWorldWebProject/index.jsp ,在输入框中输入1,运行如下图所示:
这里,我们的 JavaBean采用的是直接调用SessionBean,在实际的运用中,我们也可以采用前面所说的“重用Home句柄”的方法来提搞性能。
首先,我们修改我们的 JavaBean,使其采用资源引用的方式来调用SessionBean,方法如下:
打开 EmployeeJavaBean .java文件,修改其中的 private EmployeeSession getEmployeeSession() 方法。把这个方法中的:
homeObject = ctx.lookup("ejb/com/employee/session/EmployeeSessionHome");
替换为:
homeObject = ctx.lookup("java:comp/env/EmployeeSessionRef");
然后,再在左边 J2ee视图中,双击打开 ” WEB CONTENT ” 目录下的 ” WEB-INF ” 目录下的 web.xml,启动WEB部署符编辑器,然后选择中页面“引用”如下图所示:
在上图中,单击“添加” ,并修改自动产生的引用的名字为:“ EmployeeSessionRef ”,然后选中它,在右边的框中输入必要的信息,方法如下:在链接右边单击“浏览”,弹出如下图所示的对话框:
双击图中的 EmployeeSession,即可。WSAD自动把图中的框填充完毕。如下图所示,保存即可。
至此,我们己把 JavaBean调用SessionBean改为了资源引用的方式。
下面,我们来采用“重用 Home句柄”的方式来优化JavaBean调用SessionBean的性能。
为了提高 JavaBean调用SessionBean(EJB)的性能,采用同样的方式,我们先在“Java资源”下新建一个包并命名为:com.bean.ejbhelper,并在包中新建一个类,命名为: EjbHomeFindCacheHelper
其源代码如下:
package com.bean.ejbhelper;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import com.employee.session.EmployeeSession;
import com.employee.session.EmployeeSessionHome;
public class EjbHomeFindCacheHelper {
//定义所有的对SessionBean的引用名字在这里,有几个SessionBean,这里就定义几个引用常量
private static final String EmployeeSessionRef = "EmployeeSessionRef" ;
//采用单根模式
private static EjbHomeFindCacheHelper ejbHomeCache = null ;
//定义保存所有Session句柄引用的表
private Hashtable ejbHomeTable = new Hashtable();
//采用单根模式,将构造器设置为私有的
private EjbHomeFindCacheHelper(){
}
//返回表
private Hashtable getejbHomeTable(){
return ejbHomeTable;
}
private synchronized static EjbHomeFindCacheHelper getInstance(){
if (ejbHomeCache == null ){ //第一次运行为空,便构建一个,以便所有的共享
ejbHomeCache = new EjbHomeFindCacheHelper();
//构建SessionBean句柄集合
ejbHomeCache.buildHomeHandleCache();
}
return ejbHomeCache;
}
//构建出所有的SessionBean的Home句柄的集合并保存起来
private void buildHomeHandleCache(){
Context ctx = null ;
Object homeObject = null ;
EmployeeSessionHome employeeSessionHome = null ;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.ibm.websphere.naming.WsnInitialContextFactory" );
try {
ctx = new InitialContext(env);
//通过在web.xml中配置资源引用来查找EJB
homeObject = ctx.lookup( "java:comp/env/" +EmployeeSessionRef);
employeeSessionHome = (EmployeeSessionHome)PortableRemoteObject.narrow(homeObject,EmployeeSessionHome. class );
getejbHomeTable().put(EmployeeSessionRef,employeeSessionHome);
//可以在这里加入其它的对SessionBean的引用并把它放入cache表中,需要引用几个SessionBean,
//这里就加上几个查找并put的方法
} catch (Exception e){
e.printStackTrace();
} finally {
if (ctx!= null ){
try {
ctx.close();
} catch (NamingException e1) {
e1.printStackTrace();
}
} //end if
} //end finally
} //end buildHomeHandleCache
//以下所有的方法对外开放,用于外部引用实体Bean时获得实体Bean的Home句柄
//有几个实体Bean,这里就定义几个方法
public static EmployeeSessionHome getEmployeeSessionHome(){
return (EmployeeSessionHome)getInstance().getejbHomeTable().get(EmployeeSessionRef);
}
}
定义好了这个类以后,我们再次修改我们的 JavaBean,打开 EmployeeJavaBean .java文件,增加一个方法如下:
private EmployeeSession getEmployeeSessionByCache(){
EmployeeSessionHome employeeSessionHome = null ;
EmployeeSession employeeSession = null ;
employeeSessionHome = EjbHomeFindCacheHelper.getEmployeeSessionHome();
try {
employeeSession = employeeSessionHome.create();
} catch (Exception e) {
e.printStackTrace();
}
return employeeSession;
}
即可,然后把原来调用 getEmployeeSession ()的地方改为 getEmployeeSessionByCache ()即可。
测试方法同前一样 ,在此不再详解。最后,你的工作区形成了如下图所示的情况:
到此为止,我们详细说明了一个 CMP实体Bean的开发过程及其客户端的开发过程。
希望你能有所收获。任何意见和建议请和我联系。
四、作者介绍 abnerchai( 柴政 ), 24岁,西南交通大学计算机与通信工程学院~计算机应用技术硕士研究生、高级程序员。熟悉VC++/JAVA编程,主要研究方向为:网络安全,j2EE/中间件技术,工作流。个人联系方式为:josserchai@yahoo.com ;目前在成都美森系统软件有限公司兼职从事基于IBM WAS/WSAD平台的J2EE/EJB/JCE/JMS/JDBC/Servlets/JSP/JavaScript/开发。