利用EjbProxy
调用远程EJB的一个简单有效的class
摘要:
这个技巧告诉你如何利用EjbProxy,它提供了一些事例,调用远程EJB并不是直接与你的代码接合执行一个特殊的EJB。
By Gorsen Huang
Translator Biggie
如果你经常采用EJB开发,你或许从客户机程序那里写代码访问EJB或者写代码访问其它EJB。通常情况下,执行这些代码仅需要一些很少的变化。一个好的程序员大多数情况下处理这个问题用拷贝和贴切。然而,拷贝和贴切几次后,它会变得让人烦燥。 那就是为什么我决定开发一个class让它帮我去做,我把它叫EjbProxy,用它使得代码保持干净和整洁,这个类在调用任何EJB都不需要知道EJB的jndi name,并且可以在客户端或是EJB里使用它。
你必须遵循4种基本的措施来调用EJB
1. 创建一个jndi上下文(initial context)
2. 在上下文中查找EJB name (look up the EJB name in context)
3. 取得EJB对像
4. 通过home对像的create()方法创建EJB实例对像
1-3步具体实施如下:
InitialContext ctx = new InitialContext (prop);
Object home = ctx.lookup(beanName);
EJBHome obHome =
(EJBHome) PortableRemoteObject.narrow (home, EJBHome.class);
如你所见,你得到一个EJB name Object不需要知道具体的执行细节,除用jndi查找以外。
第4步不是简单易懂的,当你试图用home对像去创建一个EJB 对像的时候,一旦EJBHome 接口没有定义create()方法时,你就不能通过home 对象调用create() 方法,只是实际上执行EJB实现这个方法。
作为一个可行的解决方法,你可以定义一个接口去继承EJB home并且声名create()方法,然后你可以简单的用home对像的这个接口并且访问create()方法。然而,这种方法有一个缺点:它需要所有的EJB实现这个接口,从任意的home接口中,调用你想调用的create()方法。
一个更好的解决方法是你可以使用java的反射能力(关于反射API的详细资料请参考Resources)利用reflection (反射)API你可以用Class.forname方法加载指定的class,然后访问getDeclaredMethod()方法重新声明class,你能用Method.invoke 执行这种方法。
以下代码是使用反射从home对像中获得EJB的实例对像:
Method m = obHome.getClass().getDeclaredMethod("create", new Class[0]);
Object objRemote = m.invoke (obHome, new Object[0]);
Object obj = PortableRemoteObject.narrow(objRemote, theClass);
即,这段程序片断是从home对像中得到class,并且通过访问getDeclaredMethod()以create()方法名称获得create
's Method
对像。此外用invoke()方法执行create方法,返回EJB的实例对像。
The EjbProxy class
EjbProxy class,源代码EjbProxy.java,为你处理这些令人讨厌的细节。
用EjbProxy相当简单,首先创建一个EjbProxy对像,你可以传递参数,例如用initial context 工厂 和provider URL去创建initial context对像。然后访问getObj()方法用jndi查找EJB获得EJB实例对像。注意,当你从一个EJB调用另一个EJB涉及到名称时,你可能需要填加lookup name的一个环境字符串,例如java.comp/env/.
例子程序download 它将显示给你如何用EjbProxy去调用一个EJB。测试目的,我同样执行一个EJB,名字叫EjbProxyExample,它有一个pulbic 方法
public String hello (String name) throws RemoteException;
这个方法传入一个名称字符串并且返回一个”hello”组成的字符串变量,EjbProxy的jndi名称例子如下:com.javaworldtip.ejbproxyexample.EjbProxyExample,
假设你用weblogic在本地的7001端口去构造和发布EJB,
EjbProxyExample,
客户端代码:
EjbProxy myproxy = new EjbProxy ("weblogic.jndi.WLInitialContextFactory",
"t3://localhost:7001");
EjbProxyExample obj = (EjbProxyExample)myproxy.getObj
("com.javaworldtip.ejbproxyexample.EjbProxyExample");
//now get "Hello, World!" string and show it
String strHello = obj.hello("World");
System.out.println (strHello);
如果你用这个EJB调用同一服务器内部的另一个EJB的话,代码如下:
EjbProxy myproxy = new EbjProxy ();
EjbProxyExample obj = (EjbProxyExample)myproxy.getObj
("com.javaworldtip.ejbproxyexample.EjbProxyExample ");
如果你已经在部署文件中指定了EjbProxyExample,你就可以直接用getObj()方法:
EjbProxyExample obj =
(EjbProxyExample) myproxy.getObj ("java:comp/env/EjbProxyExmaple");
How it works(它是如何工作的)
你可以扩展构造器或setContextProperties()方法;
public void setContextProperties (String initContextFactory,
String providerUrl,
String user,
String password)
{
_prop = new Properties ();
_prop.put (Context.INITIAL_CONTEXT_FACTORY, initContextFactory);
_prop.put (Context.PROVIDER_URL, providerUrl);
if (user != null)
{
_prop.put(Context.SECURITY_PRINCIPAL, user);
if (password == null)
password = "";
_prop.put(Context.SECURITY_CREDENTIALS, password);
}
}
所有的参数都是创建initContext的环境,包括initcontext工厂,provider URL,用户名,密码,如果你用这个类在同一容器中重新得到EJB,你可以简单的传入null或是干脆不用理睬他们。
现在,让我们看一看在我们的代理类中的重要方法,getObj()
public Object getObj (String beanJndiLookupName) throws EJBException
{
try
{
EJBHome obHome = getHome (beanJndiLookupName);
//get the method of create
Method m = obHome.getClass().getDeclaredMethod("create", new Class[0]);
//invoke the create method
Object obj = m.invoke (obHome, new Object[0]);
return obj;
}
catch (NoSuchMethodException ne)
{
throw new EJBException (ne);
}
catch (InvocationTargetException ie)
{
throw new EJBException (ie);
}
catch (IllegalAccessException iae)
{
throw new EJBException (iae);
}
}
在getObj()方法里,唯一需要的参数就是EJB查找的jndi name,这个方法首先调用了一个gethome()方法来获得EJBhome对像,然后调用getDeclaredMethod()
方法获得create方法。一旦create被捕获,你就可以调用它并取得EJB的实例对像,如果发生意外的话,将抛出一个异常。
你必须处理一些可能发生的异常,例如:如果EJB没有声名create方法,方法
getDeclaredMethod()
将抛出
NoSuchMethodException
异常,在这段程序中,各种各样的捕捉将通过创建新的EJBException来处理这些可能发生的异常,这个方法,程序调用getObj()方法必须抛出EJBException并且适当的处理。
以下那些在getOjb()方法的getHome()方法代码如下:
public EJBHome getHome (String beanJndiLookupName) throws EJBException
{
try
{
InitialContext ctx = null;
if (_prop != null)
ctx = new InitialContext (_prop);
else
ctx = new InitialContext ();
Object home = ctx.lookup(beanJndiLookupName);
EJBHome obHome = (EJBHome)PortableRemoteObject.narrow (home, EJBHome.class);
return obHome;
}
catch (NamingException ne)
{
throw new EJBException (ne);
}
}
这个方法简单的限制了第一步到第三步调用EJB方法,我用getHome()方法正确得到我想要的home对像。I.e你想得到EJB对像,并且迟些后调用它的方法(例如调用create方法创建一个session bean)
Extend EjbProxy
针对一些情况,你可能想继承EjbProxy,例如:假设EJB’s create()方法没有任何输入参数,你可以简单的通过继承这个类用getObj去处理大多数情况:
public Object getObj (String beanJNDILookupName, Class[] classes, Object[]
objects) throws EJBException;
在方法内部,当调用getDeclaredMethod() 和invoke()
方法应用额外参数:
Method m = obHome.getClass().getDeclaredMethod("create", classes);
Object obj = m.invoke (obHome, objects);
你可以通过扩展这个类去执行任意EJB方法:
public Object executeMethod (String methodName, Class[] classes, Object[]
objects) throws EJBException;
methodName是执行方法名,在获得EJB对像之前,你可能需要在类中隐藏EJB对像。然后用类似过程修改getObj方法。
Simplify your everyday coding
利用java的反射机制,你可以用普通的柔韧性的EjbProxy,来调用本地的或是远程的或是另一个EJB,如你所见,你可以用EjbProxy 或是扩展它去实例化和调用EJB。
Resources