JiveJdon Community Forums
在线261人   首页   主题总表   培训咨询   精华   查搜   注册    登陆
首页 » 论坛 » 设计模式、框架和架构
???en_US.forumThreadPrev.name??? 上一主题
  Go back to the topic 返回本主题   Go back to the topic listing返回主题列表
???en_US.forumThreadNext.name??? 下一主题
1 2 Go 总共有 19 回复 / 2
 发表新帖子   回复该主题贴
banq

悄悄话
发表文章: 9312
注册时间: 2002年08月03日 17:08
TSS提出两种新的EJB调用模式 2004年02月29日 11:07 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
标签列表 ejb(114)      设计模式(144)      java实用系统开发指南(42)      架构比较(95)     
1. 使用reflection 技术调用EJB
http://www.theserverside.com/patterns/thread.jsp?thread_id=24019

目前JdonSD框架中的EJB调用框架实际就是这么做的,具体原理见我的书籍《Java实用系统开发指南》中“EJB方法调用框架”章节。

2.为所有的Session Bean 编写统一的Home Interface
http://www.theserverside.com/patterns/thread.jsp?thread_id=22817

这个办法是我在EJB方法调用框架之前使用的一个调用框架,《Java实用系统开发指南》书中也提及到了,也是最容易想到的,但是我发现它在JBuilder的EJB图形开发工具中无效,结果我在bean Imp中增加了新的方法,图形工具无法显示,而且,还需要在EJB-jar.xml配置两次,觉得麻烦,丢弃不用了。
holykeeper

悄悄话
发表文章: 25
注册时间: 2004年06月23日 17:23
Re: TSS提出两种新的EJB调用模式 2004年07月03日 21:35 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
banq,你好。
我想请教相关的几个问题:

1.你提到的第二个方法:“为所有的Session Bean 编写统一的Home Interface ”,是指什么?能说的详细一些吗?(链接有误,无法参考)

2.我也倾向于使用反射方法实现Session Bean的统一调用,但是我的同事提出一个疑问:在客户实现方法调用时难以确定方法的参数,就是说,在隐藏Session Bean调用的同时,丢失了一些必要的细节;同时,也无法进行编译时类型检查了。

究竟是该如何抉择?希望banq能给我指点。谢谢!
wwlhp@jdon

悄悄话
发表文章: 67
注册时间: 2003年04月25日 12:07
Re: TSS提出两种新的EJB调用模式 2004年07月04日 11:19 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
第一种方法我已经使用过了,感觉挺好。我用这种方法写了一个无状态会话bean的通用代理,已经在我们的系统中使用,效果不错。


import java.lang.reflect.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;

import com.gdpost.isp.lis.util.exception.*;
import com.gdpost.isp.lis.util.logging.*;
import com.gdpost.isp.lis.util.naming.*;

/**
* <p>Title: stateless sessionBean的动态代理。这是一个单实例类,
* 只能通过getInstance方法获得这个实例。</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2004</p>
* <p>Company: </p>
* @author wuwei
* @version 1.0
*/

public class DynamicEJBProxy {

// 私有构造函数,防止从外部创建实例
private DynamicEJBProxy () {}

private static DynamicEJBProxy singleton = new DynamicEJBProxy ();
/**
* 得到唯一的实例
* @return 本类唯一的一个实例
*/

public static DynamicEJBProxy getInstance () {
return singleton;
}

/**
* 此方法用来呼叫指定的stateless sessionBean的指定的业务方法。
* 实现过程为:
* <br>&nbsp;&nbsp;1> 根据jndiName和homeInterface找到home接口
* <br>&nbsp;&nbsp;2> 呼叫home接口的create方法,返回remote接口
* <br>&nbsp;&nbsp;3> 呼叫remote接口的业务方法,保存调用结果
* <br>&nbsp;&nbsp;4> 呼叫remote接口的remove方法
* <br>&nbsp;&nbsp;5> 返回第3步的调用接过
* @param jndiName sessionBean的JNDI名字
* @param homeInterface sessionBean的home接口类型
* @param methodName sessionBean的业务方法名字
* @param args sessionBean的业务方法参数
* @return sessionBean的业务方法返回结果
* @throws UserException 被呼叫的sessionBean的业务方法抛出的业务异常
*/

public Object invoke (String jndiName,
Class homeInterface,
String methodName,
Object[] args)
throws UserException {
try {
// 得到home stub
EJBHome homestub =
NamingLocator.getInstance().lookup (
jndiName, homeInterface);

// 调用home stub上的create方法,得到remote stub
Object remotestub = homestub.getClass ().getMethod (
"create", null).invoke (homestub, null);

// 得到remote stub上的要调用的业务方法的参数类型
Class[] paramTypes = new Class[args.length];
for (int i = 0; i < args.length; ++i) {
paramTypes[i] = args[i].getClass ();
}

// 调用remote stub上的业务方法
Object returnValue = remotestub.getClass ().getMethod (
methodName, paramTypes).invoke (remotestub, args);

// 调用remote stub上的remove方法
remotestub.getClass ().getMethod (
"remove", null).invoke (remotestub, null);

// 返回调用结果
return returnValue;
}
catch (NamingException e) {
LoggingUtil.loggingExceptionInLIS (e);
throw new UserException (
"399490000", 3, 6, "", "查询jndi出现异常");
}
catch (NoSuchMethodException e) {
LoggingUtil.loggingExceptionInLIS (e);
throw new UserException (
"399490000", 3, 6, "", "ejb没有"+methodName+"方法");
}
catch (IllegalAccessException e) {
LoggingUtil.loggingExceptionInLIS (e);
throw new UserException (
"399490000", 3, 6, "", e.getMessage());
}
catch (InvocationTargetException e) {
// 得到sessionBean的create方法、业务方法以及remove方法抛出的异常
Throwable cause = e.getTargetException();
LoggingUtil.loggingExceptionInLIS (cause);
// 判断异常的类型
if (cause instanceof CreateException) {
throw new UserException (
"399490000", 3, 6, "",
"ejb抛出CreateException");
}
else if (cause instanceof RemoveException) {
throw new UserException (
"399490000", 3, 6, "",
"ejb抛出RemoveException");
}
else if (cause instanceof RemoteException) {
throw new UserException (
"399490000", 3, 6, "",
"ejb抛出RemoteException");
}
else if (cause instanceof UserException) {
// 真正的业务异常
throw (UserException) cause;
}
else {
// 未知类型的异常
throw new UserException (
"399490000", 3, 6, "",
"ejb抛出未知类型的异常");
}
}
}

}
zhuam

悄悄话
发表文章: 67
注册时间: 2003年08月31日 13:14
Re: TSS提出两种新的EJB调用模式 2004年07月05日 08:49 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
采用反射不错,使得系统更加个灵活多变!
banq

悄悄话
发表文章: 9312
注册时间: 2002年08月03日 17:08
Re: TSS提出两种新的EJB调用模式 2004年07月05日 09:25 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
实际上这是两种模式的区别:

使用统一的接口,实际是使用Command模式,这种方式在PetStore中Web调用EJB层采用的方式,优点是Web层不需要知晓EJB的接口,通过XML文件配置。

使用反射机制,实际是一种动态代理,以方法拦截所有的调用,这种方式灵活,需要将EJB的接口方法通知Web层,EJB接口是Web开发小组和EJB开发小组所依赖,也体现了面向接口编程的OO方法吧。
banq

悄悄话
发表文章: 9312
注册时间: 2002年08月03日 17:08
Re: TSS提出两种新的EJB调用模式 2004年07月05日 09:29 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
注意:Petstore中使用Command模式还有一个缺点是: 无法实现command方法内事务机制,因为Command类是一个POJO,普通的JavaBeans,不是Session Bean,这对于事务机制要求不高的应用是可以的。
holykeeper

悄悄话
发表文章: 25
注册时间: 2004年06月23日 17:23
Re: TSS提出两种新的EJB调用模式 2004年07月06日 17:12 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
我觉得 wwlhp@jdon 的方法虽然采用了反射机制,但仍然属于Command模式。

我想采用“将EJB的接口方法通知Web层”这种方法,但在声明接口时有问题。

我的系统后台按模块分为几个Session Bean,如何为他们确定一个统一的接口?还是为每个Session Bean分别声明一个接口?

或者统一用一个Session Bean?用一个Session Bean的话,他所包含的方法就太多了!

希望得到Banq的进一步指点。
windjp

悄悄话
发表文章: 16
注册时间: 2004年02月06日 17:34
Re: TSS提出两种新的EJB调用模式 2004年07月07日 11:41 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
我觉得使用反射机制就没有了编译期检查,而且可靠性是否也值得考虑。
我的做法是为每一个调用做一个command封装,command server是一个session bean,这样也不会有事务的问题,只是这个时候写command是个繁琐的过程,其实可以通过工具做这些事,包括dto的生成等。
sanux

悄悄话
发表文章: 4
注册时间: 2004年07月07日 14:18
Re: TSS提出两种新的EJB调用模式 2004年07月07日 14:40 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
这几天我也正在解决这个问题,看了wwlhp@jdon 的代码,受益。我有两个问题:
1. invoke()首先传入参数args,然后通过
paramTypes = args.getClass ();
得到业务方法的参数。但是如果业务方法的参数是primitive,显然这种方法得到的参数类型是不正确的。例如是int型,则应该如下
paramTypes = Integer.Type;
你是怎么解决这个问题的?

2. 对Entity Bean的访问常常是用Facade模式。我用一个Session Bean做Facade,封装对EntityBean的调用。但是常常不得不为每一个EntityBean相同的方法写各自的实现。比如,每一个EntityBean的Home接口都有一个方法:
Collection findByAll();
返回remote stub的集合,然后将依次调用remote的getter方法将数据填入另一个javabean的Collection,提供给View层使用。
有没有办法使用Reflection写一个proxy实现重用?

wwlhp@jdon

悄悄话
发表文章: 67
注册时间: 2003年04月25日 12:07
Re: TSS提出两种新的EJB调用模式 2004年07月08日 18:45 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
楼上的第一个问题是可以解决的,想想一个方法如果有primitive类型的参数,你用reflection是怎么调用的。就是用对应的包装类型就可以了。
wwlhp@jdon

悄悄话
发表文章: 67
注册时间: 2003年04月25日 12:07
Re: TSS提出两种新的EJB调用模式 2004年07月08日 18:49 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
sorry,这样却是不行,会找不到方法。
holykeeper

悄悄话
发表文章: 25
注册时间: 2004年06月23日 17:23
Re: TSS提出两种新的EJB调用模式 2004年07月09日 07:54 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
我差不多想通了,使用动态代理+通用接口实现Session Bean的方法调用.
下面是代码,没有考虑异常处理、没考虑多线程:

处理事务的代码还没加上,该在那里控制事务还没想通:<
部分代码参考自wwlhp@jdon

因为还是初学,代码中有什么问题或错误还请前辈及时指出,以免我误入歧途,谢谢!


import javax.naming.*;
import java.util.Properties;
import javax.rmi.PortableRemoteObject;
import javax.ejb.*;
import java.lang.reflect.*;
...
...

class EJBInvocationHandler implements InvocationHandler {
private Object homeStub;
public EJBInvocationHandler(Object o) {
homeStub = o;
}
public Object invoke(Object proxy,Method method,Object[] args){
Object returnValue = null;
Class[] argTypes = null;
try {
Object remoteStub = homeStub.getClass().getMethod("create",
null).invoke(homeStub, null);
// 得到remote stub上的要调用的业务方法的参数类型
if(args != null){
argTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
argTypes[i] = args[i].getClass();
}
}
// 这里可以加入诸如权限控制和日志记录的代码
...
...
// 调用remote stub上的业务方法
returnValue = remoteStub.getClass().getMethod(method.getName(),
argTypes).
invoke(remoteStub, args);
// 调用remote stub上的remove方法
remoteStub.getClass().getMethod(
"remove", null).invoke(remoteStub, null);
}
catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
}

public class DynamicEJBProxy{
private Context ctx;
public DynamicEJBProxy() {
try{
//create initial context
String url =
"t3://127.0.0.1:7001";
String user = null;
String password = null;

Properties h = new Properties();
h.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
h.put(Context.PROVIDER_URL, url);
ctx = new InitialContext(h);
}
catch(NamingException e){
System.out.print(e.getMessage());
}
}
private static DynamicEJBProxy me = new DynamicEJBProxy();
static public DynamicEJBProxy getInstance() {
return me;
}
public Object createProxy(String jndi,Class clazz){
Object proxy = null;
try {
//look-up home
Object home = ctx.lookup(jndi);
Object homeStub = PortableRemoteObject.narrow(home, home.getClass());
ClassLoader loader = clazz.getClassLoader();

EJBInvocationHandler handler = new EJBInvocationHandler(homeStub);
//创建homeStub的动态代理类
proxy = Proxy.newProxyInstance(loader, new Class[] {clazz},handler);
}
catch(Exception e){
System.out.print(e.getMessage());
}
return proxy;
}

//调用方式
//SessionFacadeInterface是Web与Session Bean的通用接口
//JbPurviewManagerFacade是Session Bean的JNDI名
public static void main(String[] args){
try{
DynamicEJBProxy proxyManager = DynamicEJBProxy.getInstance();
SessionFacadeInterface proxy = (SessionFacadeInterface) proxyManager.createProxy(
"JbPurviewManagerFacade",SessionFacadeInterface.class);

//通过Web与Session Bean的通用接口调用业务方法

JbUserDto[] users = (JbUserDto[]) proxy.getAllUsers();
...
...
}
catch(Exception e){
System.out.print(e.getMessage());
}
}
}
banq

悄悄话
发表文章: 9312
注册时间: 2002年08月03日 17:08
Re: TSS提出两种新的EJB调用模式 2004年07月12日 20:56 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
非常不错,和我的书籍《Java实用系统开发指南》第七章 EJB方法调用框架思路一致的。
sanux

悄悄话
发表文章: 4
注册时间: 2004年07月07日 14:18
Re: TSS提出两种新的EJB调用模式 2004年07月19日 13:37 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
谢谢楼上各位。尽管问题解决了,我还是得马上去弄一本Benq的书来看。
linxxtao

悄悄话
发表文章: 56
注册时间: 2003年09月18日 09:46
Re: TSS提出两种新的EJB调用模式 2004年07月20日 10:45 到本帖网址 加入本帖到收藏夹 发送到手机 回复该主题
你的第一个问题没有解决吧,如果调用的方法中的参数有int,double等类型就会出现找不到方法的错误呀!
这个主题有 19 回复 / 2Go 1 2
???en_US.forumThreadPrev.name??? 上一主题
  Go back to the topic 返回本主题   Go back to the topic listing返回主题列表    返回页首返回页首
???en_US.forumThreadNext.name??? 下一主题
热点TAG: AOP cache 缓存 DDD EJB 集群 设计模式 Hibernate IOC JiveJdon OO RBAC Seam Spring Struts
正在读取,请等待...
google yahoo 新浪ViVi 365Key网摘 天极网摘 CSDN网摘 添加到百度搜藏 POCO网摘 博采网摘
查询本论坛内 回复超过的热门帖子
     回复该主题贴
标题
 
粗体 斜体 下划线 插入图片 插入代码 插入url链接 插入附件
内容
 

手机阅读 add to google add to yahoo
解惑之道在J道 ,打造中国最具影响力的的企业软件社区
OpenSource JIVEJDON v3.0 Powered by JdonFramework Code © 2002-08 jdon.com
anti spam