荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: junire (好好学习,天天向上), 信区: Java
标  题: java应用的动态扩展(二)
发信站: 荔园晨风BBS站 (Sat Nov 17 21:53:02 2001), 转信

EJB应用的扩展


在普通Java应用中使用的技术往往不适用于EJB。EJB 2.0规范建议我们只通过
Home接口创建EJB对象。之所以要强调这一点,是因为容器需要对EJB对象的创建和
拆除有更多的控制权,以便实现更好的缓冲池管理和提高代码可重用性。在EJB环
境中,所有的业务方法都在远程对象上调用,然后这些调用被传递到相应的EJB对
象上执行。因此,客户程序只需要可以在它上面调用业务方法的远程对象。下面我
们来看看如何根据指定的类名字获得EJB的远程对象。


所有EJB远程接口都必须遵循EJB规范。例如,所有的远程接口必须从一个Sun提供
的公共接口javax.ejb.EJBObject派生。由于我们要求不同的产品在动态调用时有
类似的行为模式,所以各种产品都必须从一个公共的接口Product继承,而
Product又从javax.ejb.EJBObject继承。Listing 6显示了该接口的代码。



【Listing 6:公共的Product接口】


// Product.java

package com.test.dynamic;


import javax.ejb.*;

import java.rmi.RemoteException;


public interface Product extends EJBObject

{

public float calculatePremium(

float faceValue , int term , int age) throws

RemoteException;

}





按照EJB规范,每一个Bean应该有自己的远程接口。因此,本文例子中的各种产品
都必须有自己的远程接口。容器会自动为这些远程接口提供实现。在部署Bean的时
候,容器将确保每一个Bean都有各自的远程接口。注意MediCare接口扩展自
Product接口,它不应该再定义calculatePremium()方法,因为父接口已经定义了
这个方法(见Listing 7)。图二显示了MediCare和LifeCare接口以及它们各自的
Bean实现,MediCareBean和LifeCareBean。在这里,MediCare和LifeCare接口没有
定义任何附加的方法
【Listing 7:从Product接口派生的两个接口和MediCareBean】


// MediCare.java

package com.test.dynamic;

import javax.ejb.*;

import java.rmi.RemoteException;


public interface MediCare extends Product

{

// 不再定义calculatePremium方法

}


// LifeCare.java

package com.test.dynamic;

import javax.ejb.*;

import java.rmi.RemoteException;


public interface LifeCare extends Product

{

// 不再定义calculatePremium方法

}


// MediCareBean.java

package com.test.dynamic;

import javax.ejb.*;

import java.util.*;

import javax.naming.*;


/**

* @stereotype SessionBean

* @remoteInterface com.test.dynamic.MediCareBean

* @homeInterface com.test.dynamic.MediCareHome

* @statemode Stateless

*/

public class MediCareBean implements javax.ejb.SessionBean

{

// 构造函数

public MediCareBean()

{ }


// ----------------------------------------------------

// SessionBean接口实现

public void ejbActivate(){}

public void ejbPassivate(){}

public void ejbRemove(){}

public void setSessionContext(SessionContext ctx)

{ this.ctx = ctx;

}


// -----------------------------------------------------

// create方法

public void ejbCreate(){}


// -----------------------------------------------------

// 业务方法

public float calculatePremium(

float faceValue , int term , int age)

{

float premium ;

// 执行计算

// Premium == ??

return premium;

}

// -----------------------------------------------------

private SessionContext ctx;

}





LifeCareBean的实现也相似,只是保险费计算方法的逻辑不同。Home接口都相似。
我们来看一下MediCareHome接口:



// MediCareHome.java

package com.test.dynamic;

import javax.ejb.*;

import java.rmi.RemoteException;

public interface MediCareHome extends EJBHome

{

public MediCare create() throws CreateException, RemoteException;

}





由于create()方法面向特定的Home对象,要创建某个远程接口,我们必须获得特定
的Home对象。能够创建MediCare远程对象的唯一对象是MediCareHome对象。下面是
通常使用的Home对象查找代码:



try

{

// 假定已经设置好合适的环境

Context ctx = new InitialContext(new Properties());

MediCarehome objHome = (MediCarehome) ctx.lookup("MediCarehome");

// 获得远程对象

MediCare objMediCare = objHome.create();


// 调用各种业务方法


}

catch (Exception e)

{ e.printStackTrace(); }





因此,为创建MediCare远程对象,我们需要一个MediCareHome对象(由容器实现)
。对于LifeCare远程对象来说,情况也一样。这里的关键在于要编写出通用的代码
,在Home对象上调用create()方法获取各自的远程对象。Home对象通过查找JNDI环
境获得。由于在本例中,create()方法返回一个Product类型的接口,我们可以调
用该接口的calculatePremium()方法,这个调用随后又将被分派到后台EJB的
calculatePremium()方法。

现在,为调用可能出现的未知对象上的方法,我们要用到Java Reflection API。
我们感兴趣的是java.lang.reflect包的Method类,该类代表的是一个Java方法。
java.lang.reflect.Method的invoke方法用来调用Method对象所代表的特定方法。
invoke方法的语法是:



public Object invoke(Object obj, Object [] args)





Home接口和产品的名称可以从XML文件得到(对于EJB,保存Bean的Home名称而不是
类的全称),随后这些信息就被用于通过JNDI查找Home对象。下面是XML文件的一
个片断:


【Listing 8:EJB环境下的XML文件】

<?xml version="1.0" encoding="UTF-8" ?>
<root>
<Product>
<Product-name>MediCare</Product-name>
<Home-name>MediCareHome</Home-name>
</Product>
<Product>
<Product-name>LifeCare</Product-name>
<Home-name>LifeCareHome</Home-name>
</Product>
<Product>
<Product-name>XYZCare</Product-name>
<Home-name>XYZCareHome</Home-name>
</Product>
</root>




从Home名称得到远程对象的代码封装在getProductFromHome()方法里面。它查找
Home对象,利用类的getMethod()获得一个指向create()方法的句柄。然后,它调
用不带参数的create()方法,利用Method.invoke()返回一个Product类型的接口。
参见Listing 9。



【Listing 9:根据Home名称返回远程对象】


public Product getProductFromHome(

String strHome)throws Exception

{

// 待返回的Product接口

Product prodRemote= null;


// create方法

java.lang.reflect.Method create;


// 参数类型

Class[] parameterTypes = new Class[] {};

// 参数

Object[] arguments = new Object[] {};

try

{

// 环境信息

Context ctx = new InitialContext( new Properties());

// 查找Home对象

EJBHome iHome = (EJBHome)ctx.lookup(strHome);

Class cls = iHome.getClass();


// 寻找参数类型为parameterTypes的方法

create = cls.getMethod("create", parameterTypes);

// 调用该方法获得远程接口

prodRemote = (Product)create.invoke(iHome, arguments);


}

catch( Exception e )

{

// 处理异常

throw e;

}

// 返回远程接口

return prodRemote;

}





由于我们获得的是Product类型的接口,所以可以调用该接口的
calculatePremium()方法。根据多态性原理,该调用将传递到隐藏在远程对象之后
的对象所实现的方法:



Try

{

// 获得特定产品类型的远程对象

Product objProd = getProductFromHome("MediCare");

// 调用该产品类型的calculatePremium方法

Float premium = objProd.calculatePremium(face-value, term, age);

// 显示保险费

// ......

}

catch (Exception e)

{ e.printStackTrace(); }





正如本例所示,只要更新XML文件和部署合适的EJB,我们可以添加任何额外的产品
。应用程序可以在运行时找到新的Bean并调用其calculatePremium()方法,从而提
供真正的动态扩展支持。


--
      曾经有个Cstrike的game让我痴迷,为了这份这份痴迷,我要把它记在
心里,如果Cstrike是灌冰红茶的话,我希望它永远有人喜欢,如果非要加个期限的话,
我希望是一万年。但是,我现在不得不暂时告别它了,虽然很痛苦,但我很坚定。。。。
。。。我还有更重要的事要做。。。。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.180]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店