2008年(3500)
分类:
2008-05-04 19:50:35
王晓强(forff@sina.com)
2001 年 12 月
这篇文章试图从J2EE客户端的角度出发来介绍J2EE体系。将介绍J2EE的客户端如何对EJB进行访问。J2EE的客户端分类。最后重点分析J2EE中两种相似的客户端Stand alone Client与J2EE Application Client。并会给出针对同一个Stateless Session Bean的这两种不同客户端的实现实例来具体说明它们的异同。
本文的所有实例都基于SUN的J2EE SDK进行发布。附录中也会对SUN的这个非常方便我们学习J2EE的开发工具集进行介绍。
J2EE客户端简介
J2EE的客户端,简单的说就是所有针对EJB而言都处于客户调用逻辑的组件与程序。因为J2EE结构的复杂性,J2EE客户端也比较多,一般分为以下五种。Stand
Alone Client,J2EE Application Client,JSP,Servlets,其它Enterprise JavaBeans(处于客户逻辑的EJB)。
这其中,大家对JSP与Servlets可能是比较熟悉的,因为现在基于J2EE的应用开发大部分是Broswer/Server模式,所以它们也是最常用的J2EE的客户端。而EJB本身起到客户端作用,我们也会经常碰到,比如在Session Bean中调用Entity Bean中的商业方法,那么Session Bean 就是这个Entity Bean的客户端。
谈到J2EE就不能不提到EJB。EJB是J2EE结构的核心,我们在它里面实现商业逻辑,而由实现J2EE结构的服务平台提供商为我们提供J2EE Server、EJB Container、Web Container,从而为我们提供诸如安全控制、事务处理、客户连接、以及数据库访问这些服务。这样通过对整个体系划分出不同的角色(如应用开发者,J2EE服务器提供商等等),让我们这些开发者可以专心于商业逻辑的实现,并能最大限度的实现代码的可复用性。
在EJB1.1规范中有两种EJB,一种是Session Bean另一种是Entity Bean。这两种EJB也是我们最常用到的。不论是Session Bean 还是Entity Bean它们在实现上都是由三部分组成。首先是Remote Home Interface,在这个远程接口中定义的是可由客户端调用的创建、查找(对Entity Bean而言)EJB的方法。然后是Remote Interface,这个远程接口中定义的是可供客户端访问的商业方法。最后是Bean Class,这个类对客户端而言是不可访问的,在这个类中我们要具体实现相应的商业方法,以及一些供EJB Container调用的方法。对Session Bean 与Entity Bean,以及对Entity Bean 中的bmp模式以及cmp模式而言,这个类会有很大的不同。但这不是这篇文章要重点介绍的,你只要记住对J2EE的客户端,能看到的只是Remote Interface与Remote Home Interface这两个接口而已。下面让我们看看客户端是如何具体完成对EJB的访问的。
客户端如何访问EJB
不论是那种J2EE的客户端,它要调用一个EJB的相应商业方法都要经过以下这三步:
1、 通过JNDI定位EJB的Remote Home Interface
创建JNDI名称环境,通过在发布时你给EJB定义的JNDI名称找到该EJB的Remote Home Interface。
2、 创建EJB的实例,得到Remote Interface
调用上一步得到的Remote Home Interface中的create()方法,EJB Container会创建相应EJB的实例。而你得到的就是一个定义了EJB要实现的商业方法的Remote
Interface。(EJB Container创建EJB实例的基本过程如下:客户端调用create()方法-'EJB Container实例化相应的EJB
Bean Class'EJB Container调用Bean Class中的ejbCreate方法'最后返回给我们的是EJB的Remote
Interface)
3、 调用Remote Interface中的商业方法
客户端调用上一步创建的Remote Interface中的商业方法,EJB Container就会调用相应Bean Class实例中的相应方法。
下面让我们通过具体的代码来说明这个过程。首先我们先来创建一个Stateless Session Bean。这个Session Bean实现的功能很简单,在其中的商业方法只有一个sayHello方法,打印一句"Hello World:"。如我上边所介绍的这个EJB共有三个部分,它们的源代码如下所示:
包括create()方法的Remote Home Interface接口:
|
定义商业方法的Remote Interface接口:
|
实现商业方法的Bean Class :
|
有了具体的EJB后,我们就可以看看在J2EE客户端是如何具体完成上边三步的。首先,我们通过JNDI得到HelloWorldHome接口,这个过程又分为以下几步:
Context ctx = new InitialContext();
Object ref = ctx.lookup("HelloWorld");
HelloWorldHome helloWorldHome= (HelloWorldHome)PortableRemoteObject.narrow(ref,
HelloWorldHome.class);
在我们得到了EJB的Remote Home Interface后,我们通过其中的create()方法创建一个EJB实例,并得到Remote
Interface。代码如下:
HelloWorld helloWorld = helloWorldHome.create();
现在我们就可以通过上一步得到的Remote Interface来调用我们想调用的商业方法。这里我们的EJB只实现了一个sayHello()方法。用如下的代码完成对它的调用:
helloWorld.sayHello();
所有的客户端访问EJB都是要经过以上这些步骤。Servlets一般在它的init()方法中完成创建EJB实例的步骤。而JSP访问EJB,最好都通过Java Beans来实现,所以一般在相应Java Bean的初始化方法中完成创建EJB的步骤。当然你也可以根据自己的需要在任意地点完成这些步骤。
这篇文章试图从客户端的角度来向大家介绍J2EE结构,而不是只对客户端进行介绍。所以在这里还有一些其他的信息希望大家能了解一下。在EJB2.0规范中,有一些新的情况出现了,可以对EJB进行本地访问(Local Access)。实现了本地访问的EJB像实现了远程访问的EJB一样有两个接口供客户端访问。一个是Local Interface它像Remote Interface一样定义要实现的商业逻辑。一个是Local Home Interface,它提供创建EJB以及查找(对Entity Bean而言)方法,就像Remote Home Interface一样。这两个Local Interface是供客户端访问而用,而对EJB的实现仍然在Bean Class中。对客户端而言,如果它要访问一个只有本地接口的EJB,那么它必须要和这个EJB在同一个java虚拟机中。而对一个实现远程接口的EJB,当然没有这样的限制。本地访问会提高系统性能,而且在一些场和你必须要让EJB实现本地访问(如container-managed relationship中目标端的Entity Bean,详情请参考EJB2.0规范。一般只是在Entity Bean中实现本地访问接口)。
这样设计一个EJB时你要考虑是实现远程还是本地访问。如果你所有的组件如EJB、WEB、J2EE Client等只是发布于同一台机器上,那么你就可以选择为EJB实现本地接口(当然还有一些必须实现本地接口的情况)。如果你要考虑分布式的情况,那么实现远程访问接口是你唯一的选择。如果你的EJB使用本地访问的话,对客户端就有了一些新的变化。客户端访问实现了本地接口EJB的流程和上面介绍的访问实现远程接口EJB的过程基本一样。但在通过EJB的JNDI名称得到EJB的对象后,对其造型成相应EJB的Local Home接口时,不需要再使用javax.rmi.PortableRemoteObject中的方法,而是直接用相应对象类型造型。假设我们上边的EJB实现的是本地访问接口,那么相应客户端访问代码如下:
|
还有在EJB2.0中出现了一种新的EJB:Message-Driven Bean。这种新的EJB类型和其他两种有很大不同。首先,它不像其它两种EJB那样有自己的供客户端调用的Remote或者Local Interface,它只有一个Bean Class。而且客户端也无法定位及调用Message-Driven Bean中的方法。对客户端而言它是不可见的。
下面详细介绍一下J2EE中的两种客户端,Stand alone Client与J2EE Application Client。
Stand alone Client
这种客户端就如它的名字一样,它独立于J2EE,不是J2EE的组件。它一般用于测试我们开发的EJB。下面是一个具体的例子,它访问的EJB是上边的那个Stateless
Session Bean。
|
打开一个dos窗口,使用如下的指令编译我们的代码(请根据自己的环境对里面的参数作相应调整):
D:\j2sdkee1.3\myapp\HELLOW~1>javac -classpath .;d:\j2sdkee1.3\lib\j2ee.jar
MyStandAloneClient.java
编译完成后在运行这个例子之前,要在我们的J2EE 服务器上发布我们所实现的EJB。这里我使用的J2EE服务器是J2EE SDK 1.3,有关它的介绍请见本文的附录1--J2EE SDK1.3介绍。如何在它上边发布HelloWorld EJB的详细步骤请见附录2--发布HelloWorld Staless Session Bean。
在服务器已经启动,EJB已经发布的情况下,让我们来运行一下上边的例子,使用如下的命令运行:
D:\j2sdkee1.3\myapp\HELLOW~1>java -classpath ".;d:\j2sdkee1.3\lib\j2ee.jar;helloworldClient.jar"
MyStandAloneClient
这样你就可以在J2EE Server控制台上看到我们的MyStandAloneClient调用sayHello方法所打印出来的"Hello :)"(使用j2ee -verbose启动服务器)。
J2EE Application Client
它和Stand alone Client很像,也是一个java application,但不同的是这种客户端是J2EE组件的一种。所以要想使用这种客户端,你就要用相应J2EE服务器的应用发布工具将它发布到服务器上。因为它是J2EE的组件,它与Stand
alone Client最大不同在于它可以使用J2EE提供的服务。比如它可以由J2EE统一进行安全认证,在你运行J2EE Application
Client时系统会自动弹出一个认证窗口,你输入J2EE服务器上许可的用户名和密码后才能运行这个程序,从而访问J2EE Server上的EJB。它给我们开发带来的好处是可想而知的。
还有在J2EE Application Client中,你可以通过为已有的EJB加入JNDI参考来用自己定义的JNDI名称访问EJB。例如在我的例子中是通过下面的代码来得到EJB对象的:
Object objref = initial.lookup("java:comp/env/ejb/hai");
大家也许记得在Stand alone Client例子中,我是通过"HelloWorld"JNDI名称得到同样的对象的。而这里却是"ejb/hai"。用不同的JNDI名称来访问同一个EJB。这样做的好处就是你可以随意更改你的EJB的JNDI名称,而J2EE Application Client程序代码不需要有任何更改,只需要修改EJB参考中的对应关系就可以了。这里是源代码:
|
创建好J2EE Application Client组件并将我们的应用发布后,现在就可以运行我们的J2EE Application Client了。这里我们要用到J2EE
SDK1.3为我们提供的一个运行J2EE Application Client的批处理命令runclient(在
D:\j2sdkee1.3\myapp\HELLOW~1>runclient -client helloworld.ear -name
J2EEAPPClient
这时会出现一个认证窗口,输入用户名guest和密码guest123(系统缺省提供的用户):
然后就可以在J2EE Server的控制台看到结果了,输出Hello :)。
相应的在我们运行J2EE Application Client的控制台也会在执行过程中打印出如下信息:
|
从发布J2EE Application Client组件过程以及运行过程,你已经看到了它与Stand Alone Client的两个最大的不同,一个是我们重新用另一个JNDI参考名称"hai"来访问EJB,另一个是在运行的时候系统会对我们进行认证。J2EE Application Client可以有很多实际的用途,比如可以用它在我们的系统中实现后台管理功能。
这篇文章是我自己在学习J2EE时的一些心得。对J2EE而言,核心当然还是EJB,尤其是EntityBean。希望我这篇文章能从另一个角度给大家一些帮助。如有任何问题请大家与我联系 forff@sina.com 。
附录1 J2EE SDK1.3介绍
J2EE SDK 1.3是SUN对J2EE规范的最新实现,它包含J2EE Application Server和大量其它非常有用的开发工具。它支持下面这些技术:
|
j2ee.bat:启动J2EE Server的命令。一般在命令提示符下直接敲入,即可启动服务。在这里我们用j2ee -verbose来启动服务器,这样我们输出的信息才能在控制台上显示出来。
deploytool.bat:构造及发布j2ee应用的工具。如果你直接敲入deploytool命令系统会启动一个可视化的发布工具。
runclient.bat:一个方便我们运行J2EE Application Client的工具。
在我们配置好环境参数后,只要直接启动这些命令就可以完成相应的工作。有关J2EE SDK 1.3的详细情况还请参考它的文档(在
附录2--发布HelloWorld Staless Session Bean
下面我们来看怎么在J2EE SDK1.3中发布这个Session Bean。
第一步:创建J2EE 应用
在J2EE SDK 1.3中你是不能直接把EJB发布出去的。你需要把EJB添加到一个已有的J2EE应用中去,然后再发布。这里我们先创建一个新的名叫J2EEClientTest的应用。这个应用最终被保存为helloworld.ear。下面是具体的步骤:
1、 打开一个dos窗口,启动j2ee服务器。
j2ee -verbose (只有用这种模式启动,我们才可以看到程序中的输出)
2、 再打开一个dos窗口,启动应用发布工具:
deploytool
这个命令会启动一个如下图所示的发布工具:
3、 下面我们来创建一个新的J2EE应用。
A、 在上图所示的菜单中选择[File]--〉[New]--〉[Application]。或者直接选择窗口上的New Application快捷方式。
B、 这时会弹出一个对话窗口。在Application File Name输入框输入你保存这个应用的文件名:*.ear,我这里用的是helloworld.ear。在Application Display Name 输入框输入这个应用的显示名称,我这里用的是J2EEClientTest。选择ok后我们就创建好了一个新的应用。
4、 下面我们在这个新应用中加入我们的EJB组件。
A、编译好我们的EJB的3个类,我们在dos窗口下用如下的命令完成编译:
D:\j2sdkee1.3\myapp\HELLOW~1>javac -classpath ;.;d:\j2sdkee1.3\lib\j2ee.jar
-d . HelloWorldHome.java HelloWorld.java HelloWorldBean.java
编译成功后的类会在当前的目录下的com\javausr\example目录中。
B、选择[File]--〉[New]--〉[EnterpriseBean](或者直接选择窗口上的New EnterpriseBean快捷方式)将会出现如下所示的New EnterpriseBean Wizard(跳过introduction窗口):
在JAR Display Name中填入HelloWorldEJB。在下面的Contents中将我们编译好的类加入进去。
c、选择NEXT按钮。进入下一个界面,在其中将这个EJB配置为Stateless Session Bean,并为相应的部分指定已经编译好的类。最后结果如下图所示:
d、一直选择NEXT按钮直到出现Security配置窗口,如下图:
在其中选择Deployment Settings ,会弹出上图中间的那个对话窗口,在其中选择Support Client Choice选项,然后确定。这个时候我们就可以选择Finish按钮了。这样我们新的EJB就创建好了。
第二步:发布这个应用,也就是发布了这个应用中的EJB。
1、 选择[tools]--〉[Deploy]或者窗口中的Deploy的快捷方式,会弹出如下窗口:
在其中选择Return Client Jar,而下面则会缺省生成一个返回文件的名称。这个jar文件中包括了供Stand Alone Client与J2EE Application Client访问EJB使用的一些类,是远程访问必备。选择NEXT,进入下一步。
2、 这一步我们要为EJB指定JNDI名称,以便客户端可以访问到它。如下图所示,我们输入"HelloWorld"做为JNDI名称。
现在选择Finish按钮,我们的应用就可以发布到指定的服务器上,现在可以通过客户端来访问我们的EJB了。
附录3--创建J2EE Application Client组件
J2EE Application Client也是J2EE组件中的一种,我们要运行它就要先在J2EE SDK 1.3中已有的应用中添加一个J2EE
Application Client组件。
第一步:在上一个附录中创建的应用中,加入J2EE Application Client组件。
1、 编译我们的源代码,使用如下指令:
D:\j2sdkee1.3\myapp\HELLOW~1>javac -classpath .;d:\j2sdkee1.3\lib\j2ee.jar
MyJ2EEAPPClient.java
2、 启动J2EE服务器
j2ee -verbose
3、 启动发布工具deploytool。
Deploytool
4、 选择[File]--〉[New]--〉[Application Client Compoent]或者New Application Client Compoent的快捷方式。
5、 跳过介绍页面,在JAR File Contents中加入我们编译后的.class文件,如图所示:
在其中还要选择好J2EE Application Client要归属的应用。
6、 选择NEXT,在下面的界面中,将我们的J2EE Application Client的显示名定为J2EEAPPClient如下图:
7、继续NEXT跳过Environment Entries窗口,来到Enterprise Bean References窗口,在这个窗口中为我们创建的HelloWorld EJB定义另一个JNDI参考。在我的J2EE Application Client中使用"ejb/hai"JNDI名称参考来访问我们已经发布的HelloWorld EJB。如下图:
在Home Interface与Local/Remote Interface项中分别是com.javausr.example.HelloWorldHome与com.javausr.example.HelloWorld,并在下面的Deployment Settings for ejb/hai指定我们要参考的EJB的原来的JNDI名称"HelloWorld"。现在可以选择Finish了。
第二步:发布服务,这里我们要发布已经含有J2EE Application Client组件的应用。
选择[tools]--〉[Deploy]或者窗口中的Deploy的快捷方式,会弹出如下窗口:
在其中选择Return Client Jar,而下面则会缺省生成一个返回文件的名称。这个jar文件中包括了供Stand Alone Client与J2EE Application Client访问EJB使用的一些类,是远程访问必备。
关于作者 王晓强,万千程序开发者中的一员,并乐在其中。热爱java和linux,一直利用java和xml相关技术进行应用开发,并在这些方面积累了丰富经验。E-mail:forff@sina.com |