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接口:

package com.javausr.example;
import java.rmi.*;
import javax.ejb.*;
public interface HelloWorldHome extends EJBHome {
        public HelloWorld create() throws RemoteException, CreateException;
}

定义商业方法的Remote Interface接口:

        package com.javausr.example;
import java.rmi.*;
import javax.ejb.*;
public interface HelloWorld extends EJBObject {
        public void sayHello() throws RemoteException;
}

实现商业方法的Bean Class :

        package com.javausr.example;
import java.rmi.*;
import javax.ejb.*;
public class HelloWorldBean implements SessionBean {
        private SessionContext sessionContext;
        public void ejbCreate() {}
        public void ejbRemove() throws RemoteException {}
        public void ejbActivate() throws RemoteException {}
        public void ejbPassivate() throws RemoteException {}
public void setSessionContext(SessionContext sessionContext) throws 
RemoteException {
                this.sessionContext = sessionContext;
        }
        /**唯一的商业方法*/
        public void sayHello(){
                System.out.println("Hello :)");
        }
}

有了具体的EJB后,我们就可以看看在J2EE客户端是如何具体完成上边三步的。首先,我们通过JNDI得到HelloWorldHome接口,这个过程又分为以下几步:

  1. 创建一个JNDI的名称环境: 
    Context ctx = new InitialContext(); 
    我这里的例子使用SUN的J2EE SDK1.3发布。在这个发布环境下,创建JNDI的名称环境不需要任何参数,因为这些参数都在系统启动时被自动设置好了。但如果你使用WEBLOGIC或者其它的应用服务器,就需要指定Context.INITIAL_CONTEXT_FACTORY以及Context.PROVIDER_URL参数来创建这个初始的名称环境(有过JNDI的详细情况,可以参考SUN的JNDI 部分)。
  2. 通过发布时指定给EJB的JNDI名称,得到我们需要的对象: 
    Object ref = ctx.lookup("HelloWorld"); 
    这里我给这个EJB起的JNDI名字是HelloWorld。
  3. 下面我们要将上一步得到的对象造型成HelloWorldHome对象: 
    HelloWorldHome helloWorldHome= (HelloWorldHome)PortableRemoteObject.narrow(ref, HelloWorldHome.class); 
    因为得到的是远程对象,所以这里我们要用javax.rmi.PortableRemoteObject中的方法对我们得到的对象进行造型。

在我们得到了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实现的是本地访问接口,那么相应客户端访问代码如下:

	Context ctx = new InitialContext();
	Object ref = ctx.lookup("HelloWorld");
	HelloWorldHome helloWorldHome=(HelloWorldHome)ref ;

还有在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。

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import com.javausr.example.HelloWorld;
import com.javausr.example.HelloWorldHome;
public class MyStandAloneClient {
   public static void main(String[] args) {
       try {
           //创建jndi初始化环境
           Context initial = new InitialContext();
           //找到ejb的Remote Home Interface
           Object objref = initial.lookup("HelloWorld");
           HelloWorldHome home =
               (HelloWorldHome)PortableRemoteObject.narrow(objref,
                                            HelloWorldHome.class);
           //初始化ejb,得到Remote Interface
           HelloWorld helloWorld = home.create();
           //调用商业方法sayHello()
           helloWorld.sayHello();
           System.exit(0);
       } catch (Exception ex) {
           System.err.println("Caught an unexpected exception!");
           ex.printStackTrace();
       }
   }
}

打开一个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参考中的对应关系就可以了。这里是源代码:

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import com.javausr.example.HelloWorld;
import com.javausr.example.HelloWorldHome;
public class MyJ2EEAPPClient {
   public static void main(String[] args) {
       try {
           //创建jndi初始化环境
           Context initial = new InitialContext();
           //找到ejb的Remote Home Interface
           Object objref = initial.lookup("java:comp/env/ejb/hai");
           HelloWorldHome home =
               (HelloWorldHome)PortableRemoteObject.narrow(objref,
                                            HelloWorldHome.class);
           //初始化ejb,得到Remote Interface
           HelloWorld helloWorld = home.create();
           //调用商业方法sayHello()
           helloWorld.sayHello();
           System.exit(0);
       } catch (Exception ex) {
           System.err.println("Caught an unexpected exception!");
           ex.printStackTrace();
       }
   }
}

你会发现在代码上除了上面提到的JNDI名称不同外,没有其他什么不同。但是我们不能像对Stand alone Client那样,编译完后就运行它,而要先创建一个J2EE Application Client组件,并把它加入到我们的应用中。有关这个创建过程请参考文章附录3--创建J2EE Application Client组件。

创建好J2EE Application Client组件并将我们的应用发布后,现在就可以运行我们的J2EE Application Client了。这里我们要用到J2EE SDK1.3为我们提供的一个运行J2EE Application Client的批处理命令runclient(在\bin 目录下,将它拷到含有编译后的class文件的目录中)。最后我们使用如下的命令运行: D:\j2sdkee1.3\myapp\HELLOW~1>runclient -client helloworld.ear -name J2EEAPPClient

这时会出现一个认证窗口,输入用户名guest和密码guest123(系统缺省提供的用户):


 

然后就可以在J2EE Server的控制台看到结果了,输出Hello :)。

相应的在我们运行J2EE Application Client的控制台也会在执行过程中打印出如下信息:

Initiating login ...
Username = null
Binding name:`java:comp/env/ejb/hai`
Unbinding name:`java:comp/env/ejb/hai`

从发布J2EE Application Client组件过程以及运行过程,你已经看到了它与Stand Alone Client的两个最大的不同,一个是我们重新用另一个JNDI参考名称"hai"来访问EJB,另一个是在运行的时候系统会对我们进行认证。J2EE Application Client可以有很多实际的用途,比如可以用它在我们的系统中实现后台管理功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值