我的Session Bean Container实现(2)
来源:互联网 发布:linux crontab e 编辑:程序博客网 时间:2024/05/01 15:46
第二节 一个执行Bean的通用框架
上面的例子中,客户端程序是通过网络来调用的。我们首先也不要求那么的复杂,只要写一个能够本地的Session Bean的框架就可以了。
Home接口和Remote接口都是没有实现的,要调用Home接口和Remote接口的方法,一定要实现Home接口和Remote接口。但是我们真的要一个一个地去实现他们吗?显然即使能够实现,也不是好的方案。还好,Java从1.3提供的
Proxy机制可以帮助我们实现一个通用的Home接口和Remote接口。下面让我们先来了解Proxy吧。
Proxy用于动态地创建一个或多个接口的“实现“。这里所说地“实现”并不是调用Proxy的方法后,就有新的实现接口的二进制代码产生。只是用Proxy动态创建的对象(准确地说是Proxy对象)可以将用户的调用进行拦截,拦截的内容包括:方法名和用户传递的参数。
有点抽象吧,让我们以创建 CartHome接口的Proxy对象为例来帮助我们理解Proxy。为了创建一个接口的Proxy对象,先要创建一个Proxy类。
下面是创建CartHome接口的代理类的代码
Class cartHomeProxyClass = Proxy.getProxyClass( CartHome.class.getClassLoader(),
new Class[]{CartHome.class} );
Proxy.getProxyClass()有两个参数,第一个参数为ClassLoader,表示我们创建的cartHomeProxyClass代理类由这个ClassLoader管理。第二个参数表示我们要在新创建的Proxy类“实现”哪几个接口。这里我们只实现了CartHome接口。
Proxy类创建好了以后,就可以调用它的构造函数创建一个Proxy对象,下面为创建CartHome的Proxy对象代码:
InvocationHandler handler = new CartHomeInvocationHandler(…);
CartHome cartHome = (CartHome) cartHomeProxyClass.getConstructor(
new Class[] {InvocationHandler.class }).
newInstance(new Object[] { handler });
我们用两步创建了一个Proxy对象,Proxy中提供了newProxyInstance()方法可以将上面的两步合为一步创建Proxy对象。一步创建CartHome Proxy对象的代码为:
InvocationHandler handler = new CartHomeInvocationHandler(…);
CartHome cartHome = (CartHome) Proxy.newProxyInstance( CartHome.class.getClassLoader(),
new class[]{CartHome.class},
handler );
在创建Proxy对象的时候,要一个InvocationHandler对象。上面所说的Proxy对象拦截的用户调用的内容就会传入到我们实现的InvocationHandler对象中。InvocationHandler的声明为:
public interface InvocationHandler {
public Object invoke( Object proxy,
Method method,
Object[] args )
throws Throwable;
}
当用户调用cartHome.create( “Xiao Min” )时,CartHomeInvocationHandler实现的invoke()方法就会被调用,参数包括:
1) proxy,就是用CartHome的Proxy类创建的Proxy对象,即cartHome对象。
2) method就是CartHome接口的create(String person)方法。
3) args就是调用create(String)方法时用户传入的参数,即“Xiao Min”
对被拦截的cartHome.create(String person)方法在InvocationHandler.invoke()中进行解释执行,返回同CartHome.create(String person)返回类型一样的对象(即Cart类型对象)。对CartHome方法调用进行拦截的InvocationHandler代码框架如下:
public class CartHomeInvocationHandler implements InvocationHandler {
//变量声明
...
public CartHomeInvocationHandler(...) {
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
Cart cart = ...;
....;
return cart;
}
}
现在我们可以对调用一个接口的Proxy对象的方法进行拦截,解释,执行并返回所要求得结果类型了。
因为Cart类也是一个接口类,所以也要用Proxy创建一个Cart的Proxy类。因此,CartHomeInvocationHandler的定义可以细化为:
public class CartHomeInvocationHandler implements InvocationHandler {
public CartHomeInvocationHandler(...) {
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
InvocationHandler handler = CartInvocationHandler(...);
Cart cart = (Cart)Proxy.newProxyInstance( proxy.getClass().getClassLoader(),
new Class[]{Cart.class},
handler );
....;
return cart;
}
}
根据Sun的EJB规范,对被创建的Cart Proxy对象的方法进行调用,就是对某个CartBean对象的同名方法(指方法明,参数类型和返回类型都相同)进行调用。因此,被创建的Cart Proxy对象中用到的CartInvocationHandler类可以写为:
public class CartInvocationHandler implements InvocationHandler {
private CartBean cartBean_;
public CartInvocationHandler( CartBean cartBean ) {
cartBean_ = cartBean;
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
Method m = cartBean_.getClass().getMethod( method.getName(),method.getParameterTypes() );
if( m != null )
return m.invoke( cartBean_, args );
throw new RemoteException( "Fail to find the method:" + method );
}
}
这里我们忽略了对异常的处理。我们利用Java的反射机制寻找在CartBean对象中对应的方法并对它进行调用。
如果用户每调用一个代理对象cartHome的create方法时,创建一个新的CartBean对象的话,CartHomeInvocationHandler类的定义就可以为:
public class CartHomeInvocationHandler implements InvocationHandler {
public CartHomeInvocationHandler(...) {
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
CartBean cartBean = new CartBean();
InvocationHandler handler = CartInvocationHandler(cartBean );
Cart cart = (Cart)Proxy.newProxyInstance( proxy.getClass().getClassLoader(),
new Class[]{Cart.class},
handler );
…
return cart;
}
根据Sun EJB Container规范,Session Bean的Home接口中定义的create方法应该调用Bean中对应的ejbCreate()方法,CartHomeInvocationHandler可进一步细化为:
public class CartHomeInvocationHandler implements InvocationHandler {
public CartHomeInvocationHandler() {
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
CartBean cartBean = new CartBean();
InvocationHandler handler = CartInvocationHandler(cartBean );
Cart cart = (Cart)Proxy.newProxyInstance( proxy.getClass().getClassLoader(),
new Class[]{Cart.class},
handler );
if( method.getName().equals( “create” ) ) {
Method m = cartBean.getClass().getMethod(“ejbCreate”,
method. GetParameterTypes() );
if( m == null ) throw new RemoteException(“fail to find the ejbCreate()”);
m.invoke( cartBean, args );
}
return cart;
}
到现在为止我们已经完成了CartHomeInvocationHandler和CartInvocationHandler类, 可以编写测试程序来测试一下了。
InvocationHandler handler = new CartHomeInvocationHandler();
CartHome cartHome = (CartHome) Proxy.newProxyInstance( CartHome.class.getClassLoader(),
new class[]{CartHome.class},
handler );
Cart cart = cartHome.create( "Xiao Min" );
cart.addBook( "Effective Java");
cart.addBook( "Master Java");
Vector books = cart.getContents();
for( int i = 0, n = books.size(); i < n; i++ ) {
System.out.println( books.get( i ) );
}
虽然,我们没有实现CartHome接口和Cart接口,但是通过运用Java的Proxy机制,我们可以执行CartBean中的方法了。
如果为每一个具体的Home接口和Remote接口都编写各自的InvocationHandler,虽然工作量不大,但是不能做到通用。能不能够为所用的Home接口和Remote接口编写通用的InvocationHandler呢?答案是肯定的。我们分析一下如何编写通用的InvocationHandler。
先考察Remote接口的通用InvocationHandler的编写。虽然我们传递到CartInvocationHandler构造函数的参数类型是CartBean,但是在CartInvocationHandler.invoke()方法中调用CartBean的方法是使用反射机制。这就是说我们只传递一个Object对象到CartInvocationHandler中,CartInvocationHandler.invoke()也可以工作。我们将CartInvocationHandler改名为RemoteInvocationHandler以表示我们编写的是一个通用的Remote接口的InvocationHandler。RemoteInvocationHandler的新代码如下:
public class RemoteInvocationHandler implements InvocationHandler {
private Object bean_;
public RemoteInvocationHandler ( Object bean ) {
bean_ = bean;
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
try {
Method m = bean_.getClass().getMethod( method.getName(),method.getParameterTypes() );
if( m != null )
return m.invoke( bean_, args );
throw new RemoteException( "Fail to find the method:" + method );
}catch( Exception ex ) {
throw new RemoteException(“Fail to execute method:” + method, ex );
}
}
}
再考察Home接口的通用InvocationHandler的编写。在CartHomeInvocationHandler中,每次调用CartHomeInvocationHandler.invoke()时,都要创建一个CartBean对象。如果我们有什么方法只要知道CartBean的名字,也能创建CartBean的话,那么我们的CartHomeInvocationHandler就可以改造成为一个通用的InvocationHandler。
Sun的EJB规范中规定,一个Bean必须要有一个不带参数的构造函数。这就是说我们在构造Bean时不能传递参数到Bean 中。如果要传递参数的话就只能通过函数调用。EJB规范中,我们在构造好Bean以后,可以立即调用ejbCreate方法传递参数到Bean中(在这一点上,Sun完全没有遵守面向对象的守则,只是用一种约定)。既然Bean中一定有一个不带参数构造函数,我们完全可以用Bean的名字构造一个Bean对象。将CartHomeInvocationHandler名字改为HomeInvocationHandler以表示我们编写的是一个通用的Home接口的InvocationHandler,其代码如下:
public class HomeInvocationHandler implements InvocationHandler {
private String remoteClassName_;
private String beanClassName_;
public HomeInvocationHandler( String remoteClassName, String beanClassName ) {
remoteClassName_ = remoteClassName;
beanClassName_ = beanClassName;
}
public Object invoke( Object proxy,
Method method,
Object[] args ) throws Throwable
{
try {
Class beanClass = Class.forName( beanClassName_ );
Class remoteClass = Class.forname( remoteClassName_ );
Object bean = beanClass.newInstance();
InvocationHandler handler = RemoteInvocationHandler(bean );
Object proxyObj = Proxy.newProxyInstance( proxy.getClass().getClassLoader(),
new Class[]{remoteClass },
handler );
if( method.getName().equals( "create" ) ) {
Method m = bean.getClass().getMethod(“ejbCreate”,
method. getParameterTypes() );
if( m == null ) throw new RemoteException(“fail to find the ejbCreate()”);
m.invoke( bean, args );
}
return proxyObj;
}catch( Exception ex ) {
throw new RemoteException( “fail to call the method:” + method, ex );
}
}
}
使用新编写的HomeInvocationHandler和RemoteInvocationHandler,我们的测试代码就变为:
InvocationHandler handler = new HomeInvocationHandler( “Cart”, “CartBean”);
CartHome cartHome = (CartHome) Proxy.newProxyInstance( CartHome.class.getClassLoader(),
new class[]{CartHome.class},
handler );
Cart cart = cartHome.create( "Xiao Min" );
cart.addBook( "Effective Java");
cart.addBook( "Master Java");
Vector books = cart.getContents();
for( int i = 0, n = books.size(); i < n; i++ ) {
System.out.println( books.get( i ) );
}
如果进一步可以将Home接口的代理对象的创建封装起来,就更是完美了。我们将他封装到HomeProxyFactory类中吧。因此,HomeProxyFactory可以写为:
public class HomeProxyFactory
{
public static Object createHomeProxy( String homeClassName, String remoteClassName, String beanClassName ) {
try {
InvocationHandler handler = new HomeInvocationHandler ( remoteClassName, beanClassName );
Class homeClass = Class.forName( homeClassName );
return Proxy.newProxyInstance( homeClass.getClassLoader(), new Class[]{homeClass}, handler );
}catch( Exception ex ) {
throw new RuntimeException( ex );
}
}
}
测试代码引用新创建的HomeProxyFactory的话,测试代码就变为了:
CartHome cartHome = (CartHome) HomeProxyFactory.createHomeProxy( “CartHome”, “Cart”, “CartBean”);
Cart cart = cartHome.create( "Xiao Min" );
cart.addBook( "Effective Java");
cart.addBook( "Master Java");
Vector books = cart.getContents();
for( int i = 0, n = books.size(); i < n; i++ ) {
System.out.println( books.get( i ) );
}
是不是很简单?
- 我的Session Bean Container实现(2)
- 我的Session Bean Container实现(1)
- 我的Session Bean Container实现(3)
- Session Bean 的生命周期
- Session Bean 与 Entity Bean 的区别?Stateful Session Bean 与 Stateless Session Bean 的区别?
- ejb3(session bean)会话bean的使用!!!
- Session Bean的生命周期事件
- EJB---->Session Bean 的生命周期
- session/application/bean的学习
- Stateless Session Bean的用法
- Stateless Session Bean 与Stateful Session Bean 的比较
- 歪解stateful session bean 和 stateless session bean的区别。
- 腾讯云的Container实现
- 腾讯云的Container实现
- Session Bean
- session bean
- session bean
- session bean
- 小康淘宝站内信群发 v5.50 怎么用
- 小恐龙成语辞典 v3.1 免费
- 小恐龙网页转换器 v1.1 下载
- 小恐龙ftp v1.5 bt
- 小精灵家庭理财 v3.01 是什么
- 我的Session Bean Container实现(2)
- 小精灵定时关机 v1.0 绿色
- mfc常用方法
- 小精灵 pacmania ii v1.4 官网
- 小蒋家庭影音平台 v2006 build 0909 是什么
- 小军五子棋 v3.0 官网
- 小蒋搜搜(xp search) v1.03 绿色
- zju题目推荐
- 小蒋上门(家庭版) v2006 build 0920 免费