版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 Enterprice JavaBeans 是一个用于分 布式业务应用的标准服务端组件模型。采 用Enterprice JavaBeans 架构编写的应 用是可伸的、事务性的、多用户安全的。 可以一次编写这些应用,然后部署在任何 支持Enterprice JavaBeans 规范的服务 器平台,如jboss、weblogic 等。 Enterprise JavaBean(EJB)定义了三种企业Bean,分别是 会话Bean(Session Bean),实体Bean(Entity Bean)和消息 驱动Bean(MessageDriven Bean)。 会话Bean 会话Bean 用于实现业务逻
2、辑,它分为有状态bean 和无状态bean。 每当客户端发出EJB 调用请求时,容器就会选择一个Session Bean 来为客户端服务。会话Bean 可以直接访问数据库,但更多时候,它 是通过实体Bean 实现数据访问。 实体Bean: 从名字上我们就能猜到,实体bean 代表真实物体的数据。在 EJB3.0 中,实体bean 仅作为普通Java 对象来使用,它负责跟数 据库表进行对象与关系映射(O/R Mapping)。 消息驱动Bean(MDB): MDB 是设计用来专门处理基于消息请求的组件。它能够收发异步 JMS 消息,并能够轻易地与其他EJB 交互。它特别适合用于当一个 业务执行的
3、时间很长,而执行结果无需实时向用户反馈的这样一个场 合。 EJB 需要运行在EJB 容器,每个JavaEE 应用服 务器都含有EJB 容器和Web 容器,所以既可以运行 EJB,也可以运行Web 应用。目前支持EJB3.0 的应 用服务器有Jboss(4.2.x 以上版本)、Glassfish、 Weblogic(10 以上版本)、Sun Application Server(9.0 以上版本)、Oracle Application Server(10g 以上版本)和我们国内的apusic 应用服 务器。本书将介绍Jboss 和Weblogic,前者是使用者 最多的开源应用服务器,后者是市场占
4、有率最高的商业 应用服务器。 注意:Tomcat 目前只是Web 容器,它不能运行EJB 应用。 JNDI 是自JDK1.3 版本开始就绑定的标 准Java API。它为各种现有的命名和目录服 务提供了通用接口:DNS、LDAP、活动目录 (Active Directory)、RMI 注册器、COS 注册器、NIS 及文件系统。在结构上,JNDI 由两部分组成:客户API 和服务提供商接口 (Service Provider Intergace,SPI),应 用程序通过客户API 访问命名和目录服务;服 务提供商接口用于供厂商创建命名和目录服务 的JNDI 实现。下面是JNDI 的结构图: 对
5、于EJB 开发者来说,我们只需要知道使用客户API 如 何访问命名和目录服务即可,而不需要知道JNDI SPI 的使用, 因为我们不需要使用JNDI SPI 开发JNDI 实现产品,这就好 比通过JDBC 访问数据库,我们只需要知道使用JDBC API 如何访问数据库,而不需要知道数据库的JDBC 驱动如何实现。 使用客户API 访问EJB3.0,我们需要编写的JNDI 代码不过 几句,所以大家不要被吓倒了。 命名服务用于将名称和对象联系起来,使得我们可以用名 称访问对象。例如,当你在web 浏览器输入URL: http:/ 时,DNS(Domain Name System,域名系统)将这个域
6、名转换成IP 地址。 目录服务是命名服务的自然扩展,在这种服务里,对象不 但有名称,还有属性。与命名服务的关键差别是:目录服务中 对象可以有属性(例如,用户有email 地址),而命名服务中 对象没有属性。 进入 http:/ 下载 JDK。在页面中找到JDK 5.0 Update 14(版本在不断更新中,有 可能大于14),点击右边的Download,注意中间有Accept 和 Decline 两选项,点选Accept。在Windows Platform 一栏找到 Windows Offline Installation, Multi-language 这个链接,点击 下载。(注:本书光盘“
7、软件”文件夹中带有JDK 5.0) 按照安装向导提示安装,安装路径选择C:Javajdk1.5.0_14。 Jdk 安装完后,接着问你是否安装jre,也一起安装上。 右键点击“我的电脑”-“属性”-“高级”-“环境变量”, 在“系统变量”里添加JAVA_HOME 变量,值为JDK 的安装路径, 如:C: Javajdk1.5.0_14。 在“系统变量”里再添加CLASSPATH 变量,值为:.; %JAVA_HOME%libdt.jar; %JAVA_HOME%libtools.jar;在系 统变量栏找到变量名为Path 的选项,点“编辑”在变量值的末尾添 加;%JAVA_HOME%bin;
8、进入http:/ 面,选择jboss4.2.2.GA 文件下载(大小为92MB)。下 载后直接解压缩文件即可完成安装,为了避免应用出现莫名 的错误,解压缩的路径最好不要带有空格,如“Program Files”。 安装完后请右键点击“我的电脑”-“属性”-“高 级”-“环境变量”,在“系统变量”里添加 JBOSS_HOME变量,值为Jboss 的安装路径,如: D:JavaEEServerjboss。 在系统变量一栏找到变量名为Path 的选项,点“编辑” 在变量值的末尾添加:;%JBOSS_HOME%bin;现在验证 Jboss 安装是否成功, 进入jboss 安装目录bin 目录, 双击r
9、un.bat 启动jboss。观察控制台有没有Java例外抛出, 如果没有例外并看到下图,恭喜你,安装成功了。 你可以输入http:/localhost:8080 进入Jboss 的欢迎主页。 在JBoss Management 栏点击“JMX Console”进入Jboss的管 理平台。如果需要输入用户名及密码,默认的用户名及密码都是 admin。 如果jboss 启动出错,应检查打印在Jboss 控制台的JDK 版 本是否5.0 以上,jboss 所用的端口是否被占用(如 1099,8009 ,8080 等端口)。如果端口被占用就关闭占用此 端口的进程。 如果启动时出现这样的错误:“fin
10、dstr 不是内部或外部命 令,也不是可运行的程序或批处理文件”。那么应该在系统变量 Path 中追加%SystemRoot%system32;%SystemRoot%;。 最后的办法是重装机器上的JDK,祝你好运。 在本书配套光盘的HelloWorld 文件夹下,找 到HelloWorld.jar,把该文件拷贝到“jboss 安 装目录/server/default/deploy/”目录下, jboss 会对HelloWorld 进行热部署。接下来继续 把EJBTest文件夹下的EJBTest.war 拷贝到 “jboss 安装目录/server/default/deploy/。 在浏览器上
11、输入: http:/localhost:8080/EJBTest/Test.jsp (注意大小写)。将会看见下图所示。 在JBoss 部署应用的过程非常简单、直接。在每一个配置中, Jboss 会不断扫描一个名为jboss 安装目录/server/config- name/deploy 的特定目录,查看是否有任何更新,此目录一般被称 为“部署目录”。 你可以把下列文件拷贝到部署目录中: 任何Java 库(其中的类将被自动添加到JBoss 的classpath 中) EJB-JAR WAR (Web Appliction aRrchive) EAR (Enterprise Application
12、 aRchive) 包含JBoss MBean 定义的XML 文件 以.jar、.war 或者.ear 结尾的目录,分别包含了EJB-JAR、 WAR 或者EAR 的解压缩内容。 要重新部署上述文件(JAR、WAR、EAR、XML 等),只需 用更新后的版本覆盖即可。Jboss 将通过对比时间戳来检测变化,卸 载旧文件,部署相应的新文件。如果要重新部署目录,只需更新其时 间戳即可。从部署目录中删除文件会导致相应文件从部署中卸载。 Session Bean 是实现业务逻辑的地方。 简单地说,像我们要实现两数相加或是从数据 库中读取数据,都是通过Session Bean 来实 现。根据是否可以维护
13、会话状态,Session Bean 分为有状态bean 和无状态bean。有状 态bean 可以维护会话状态,无状态bean 不 维护会话状态。要维护会话状态,意味着EJB 容器要为每个用户创建一个bean实例,并通 过该实例保存着与用户的会话状态。不维护会 话状态,意味着一个bean 实例不需要保存与 某个用户的会话状态,这时一个bean 实例可 以为多个用户服务。 要开发一个Session Bean,我们需要定义接口和Bean class。其中接口分为远程(remote)和本地(local)接口。在 EJB3.0中,不要求你同时实现remote 和local 接口,但实现 两者是比较好的做
14、法。 远程接口(remote interface):定义了session bean 的业务方法,这些方法可以被来自EJB 容器之外的应用访问到。 本地接口(local interface):同样定义了session bean 的业务方法,这些方法可以被同处于EJB 容器内的其它应用使 用。因为local 接口允许bean 之间直接通过内存交互,没有分 布式对象协议的开销,从而改善了性能。 Bean 类(bean class):bean class 包含了业务逻辑,它 必须具备一个远程或本地接口。在Bean 类,我们应该实现接 口的业务方法,尽管这并不是必须的,但我们没理由不这样做。 由于无状态
15、会话Bean 不维护会话状态,意味着一个bean 实例可以为多个用户服务。因此EJB 容器使用实例池化技术管 理无状态会话Bean。简单的说就是:当无状态会话Bean 部署 到应用服务器时,EJB 容器会为它预先创建一些bean 实例放 在对象池。当有用户访问EJB 方法时,EJB 容器会从对象池 中取出一个实例为之服务,服务完了就回到对象池。当下一个 用户再访问EJB 方法时,EJB 容器有可能再次把该实例取出 来为之服务。正因如此,无状态会话Bean 只需要少量的实例 就可以为成百上千的用户服务,大大提高了系统性能。 由于无状态会话Bean 能够支持多个用户,并且通常在 EJB 容器中共享
16、,可以为需要大量客户的应用提供更好的扩充 能力。无状态会话Bean 比有状态会话Bean 更具性能优势, 在条件允许的情况下开发人员应该首先考虑使用无状态会话 Bean。 在开发前,先熟悉一下本例子的调用流程图: 现在我们就开始本例子的开发。首先在 Eclipse 中新建一个普通的java 项目,然 后把Jboss 安装目录/client 下的所有jar 文件加入到项目的构建路径中。如果不需 要在项目中使用单元测试用例或普通J2SE 调用EJB,你只需要加入javaee.jar,接下 来开始代码编写。 第一步:定义一个包含业务方法的接口。这个接口不需要 包含任何注释,它是一个普通的java 接
17、口。调用EJB的 客户端使用这个接口引用从EJB 容器返回的存根(stub)。 代码如下: HelloWorld.java package com.foshanshop.ejb3; public interface HelloWorld public String SayHello(String name); 第二步:编写Bean class。 HelloWorldBean.java 。Bean 类推荐的命名方式是:接口+Bean , 如: HelloWorldBean 。 package com.foshanshop.ejb3.impl; import com.foshanshop.ejb3
18、.HelloWorld; import javax.ejb.Remote; import javax.ejb.Stateless; Stateless Remote (HelloWorld.class) public class HelloWorldBean implements HelloWorld public String SayHello(String name) return name +说:你好说:你好!世界世界,这是我的第一个这是我的第一个EJB3哦哦.; 在Bean 类上面有两个注释Stateless 和Remote,Stateless 注 释指明这是一个无状态会话Bean。S
19、tateless 注释的定义如下: Package javax.ejb; Target(TYPE) Retention(RUNTIME) public interface Stateless String name( ) default ; String mappedName() default ; name()属性用于指定session bean 的EJB 名称。该名称在EJB Jar 包中必须是全局唯一的,而在EAR 中却可以重复(因为EAR 可以包含多个 EJB Jar,而每个jar 可以存在一个同名的EJB,在EAR 中要定位某个EJB, 可以这样使用:xxx.jar#HelloWor
20、ldBean)。如果不指定该属性,默认就是 bean class 的非限定名称。对本例而言,EJB 名称默认为 HelloWorldBean。 mappedName()属性指定Bean 的全局JNDI 名称,这个属性在 weblogic,Sun 应用服务器和glassfish 起作用。 Remote 注释指定这个无状态Bean 的 remote 接口。Bean 类可以具有多个remote 接 口,每个接口之间用逗号分隔,如:Remote (HelloWorld.class,Hello.class,World.class)。 如果你只有一个接口,你可以省略大括号,对于本 例而言,可以写成这样:R
21、emote (HelloWorld.class)。 经过上面两步,一个HelloWorld EJB 就开发 完了。现在我们把它发布到Jboss 中。在发布前我 们需要把它打成Jar包。打JAR 包的方法有很多, 如使用jar 命令、集成开发工具或者Ant。 在Eclipse 开发环境下,可以通过导出向导进行打包。在项目名称上点 击右键,在跳出的菜单中选择“Export(导出)”,在“Export”对话框选 择“JAR file”,如下图: 点“Next”, 在“select the resources to export(选择要导 出的资源)”一栏, 展开你的项目并选 择需要打包的文件。 然后
22、选择一个存放 目录及文件名。点 “Finish”结束打 包。如下图: 当HelloWorld 打成jar 文件后,我们把它发布到Jboss。发布 前先检查jboss 是否已经启动,如果没有启动,我们可以进入jboss 安装目录/bin,双击run.bat 启动Jboss。不指定启动参数的情况下, Jboss 默认使用default 配置项。 把jar 文件拷贝到jboss 安装目录serverdefaultdeploy 目录。观察Jboss 控制台输出,如果没有抛出例外并看到下面的输出 界面,发布就算成功了。 当EJB 发布成功后,Jboss 容器会为它生成一个全局JNDI 名 称,我们可以利
23、用这一点进一步判断EJB 发布是否成功。我们进入 Jboss 的管理台查看它的JNDI 名称,输入下面URL http:/localhost:8080/jmx-console/ 点击service=JNDIView,查看EJB 的JNDI 名称。(如下图) 在出现的页面中,找到“List of MBean operations:”栏。 (如下图) 点击“Invoke”按钮,出现如下界面: 在出现的页面中,我们可以看到JBOSS 的 JNDI 树,它的命名约定如下: (1)java:comp (java:comp namespace) 这个上下文环境和其子上下文环境仅能被应用 组件内部访问和使用
24、 (2)java:(java: Namespace) 上下文环境和绑定的对象只能被处在同一个 JVM 内的客户访问 (3)Global JNDI Namespace 上下文环境能被所有客户访问,不管它们是否 处在同一个JVM 内。 当EJB 发布到Jboss 时,如果我们没有为它指定全局JNDI 名称或修改过其默认EJB 名称,Jboss 就会按照默认的命名规则为EJB 生成全局JNDI 名称,默认的命名规则如下: 如果把EJB 作为模块打包进后缀为*.ear 的JAVA EE 企业应用文件,默认的全局 JNDI 名称是 本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NA
25、ME/local 远程接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote EAR-FILE-BASE-NAME 为ear 文件的名称,EJB-CLASS-NAME 为EJB 的 非限定类名。 例:把HelloWorld 应用作为EJB 模块打包进名为HelloWorld.ear 的企业应用文件, 它的远程接口的JNDI 名称是: HelloWorld/HelloWorldBean/remote 如果把EJB 应用打包成后缀为*.jar 的模块文件,默认的全局JNDI 名称是 本地接口:EJB-CLASS-NAME/local 远程接口:EJB-CLASS-N
26、AME/remote 例:把HelloWorld 应用打包成HelloWorld.jar 文件,它的远程接口的JNDI 名称是: HelloWorldBean/remote 注意:EJB-CLASS-NAME 是不带包名的,如 com.foshanshop.ejb3.impl.HelloWorldBean 只需取HelloWorldBean。 如果你通过S()、S()及其等价的XML 指定了EJB 名称,那么上面的EJB-CLASS-NAME应该换为EJB 名称,此时的JNDI 名称格式如: EJB 名称/remote、EAR 文件名/EJB
27、名称/remote。 在Global JNDI Namespace 一栏,我们看到了HelloWorldBean 的远程接口的JNDI 名 称为HelloWorldBean/remote。意味着EJB 已经发布成功。接下来我们看看客户端如何访问它。 Test.jsp 在进行JNDI 查找前,我们必须设置应用服务器的上下文信息,主要是设置 JNDI 驱动的类名(java.naming.factory.initial)和命名服务提供者的URL (vider.url) 。 java.naming.factory.initial 或Context.INITIAL_CONT
28、EXT_FACTORY:环境 属性名,用于指定InitialContext工厂(作者称它为JNDI 驱动更容易理解),它类似 于JDBC 指定数据库驱动类。 因为本例子连接的是JbossNS(命名服务的实现者),所以使用Jboss 提供的驱动类: erfaces.NamingContextFactory vider.url 或Context.PROVIDER_URL:环境属性名,包含提供命 名服务的主机地址和端口号。它类似于JDBC 指定数据库的连接URL。 连接到JbossNS 的URL 格式为:jnp:/host:port,该URL 的“
29、jnp:”部分是 指使用的协议,JBoss 使用的是基于Socket/RMI 的协议。host 为主机的地址, port 为JNDI 服务的端口。除了host 之外,其他部分都是可以不写的。 除了上述两个环境属性外,还有两个环境属性是我们经常使用到的: java.naming.security.principal(或Context.SECURITY_PRINCIPAL)和 java.naming.security.credentials(或Context.SECURITY_CREDENTIALS), 这两个环境属性用于指定用户标识(如用户名)及凭证(如密码),当EJB 使用了安 全服务时,你必
30、须提供这两个属性。它类似于JDBC 指定连接到数据库的用户名及密 码。 如果客户端运行在应用服务器内,我们不 需要为InitialContext 设置应用服务器的上 下文信息,也不建议设置。因为应用服务器启 动时会把JNDI 驱动类等上下文信息添加进系 统属性,创建InitialContext 对象时如果没 有指定Properties 参数,InitialContext 内 部会调用System.getProperty()方法从系统 属性里获取必要的上下文信息。对本例子而言, 你可以省略传入props 参数。在实际应用中, 如果给InitialContext 设置了参数,反而会 带来不可移植的
31、问题。 创建InitialContext 对象时如果没有指定Properties 参 数,InitialContext 还会在classpath 下寻找perties 文件,并从该文件中加载应用服务器的上下文信息。这样避免 了硬编码为InitialContext 设置Properties 参数。 perties 的配置如下: java.naming.factory.initial=erfaces.NamingC ontextFactory vider.url=localhost:1099 java.naming
32、.factory.url.pkgs=org.jboss.naming:org.jnp.i nterfaces 当InitialContext 初始化后,我们使用EJB 的Jndi 名称 通过lookup()方法查找EJB。lookup()方法返回一个存根对象, 该存根实现了HelloWorld 接口。它负责将方法调用路由到应 用服务器,应用服务器再把方法调用请求路由到 HelloWorldBean 实例。 开发只有Local接口的无状态Session Bean的步骤和上节 开发只有Remote接口的无状态会话Bean的步骤相同,两者唯 一不同之处是,前者使用Remote注释声明接口是远程接口
33、,后者使用Local注释声明接口是本地接口。 当Local和Remote注释都不存在时,容器会将Bean class实现的接口默认为Local接口。如果EJB与客户端部署在 同一个应用服务器,采用Local接口访问EJB优于Remote接口 。因为通过Remote接口访问EJB需要在tcp/ip协议基础上转 换和解释Corba IIOP协议消息,在调用EJB的这一过程中存在 对象序列化,协议解释、tcp/ip通信等开销。而通过Local接 口访问EJB是在内存中与bean彼此交互的,没有了分布式对象 协议的开销,大大改善了性能。下面是只有Local接口的无状 态会话Bean。 业务接口:Loc
34、alHelloWorld.java package com.foshanshop.ejb3; public interface LocalHelloWorld public String SayHello(String name); Bean 类:LocalHelloWorldBean.java package com.foshanshop.ejb3.impl; import javax.ejb.Local; import javax.ejb.Stateless; import com.foshanshop.ejb3.LocalHelloWorld; Stateless Local (Loca
35、lHelloWorld.class) public class LocalHelloWorldBean implements LocalHelloWorld public String SayHello(String name) return name +说:你好说:你好!世界世界,这是一个只具有这是一个只具有Local接口的无状态接口的无状态Bean; 把上面的EJB 打成jar 文件后,发布到jboss 安装目录 serverdefaultdeploy 目录中。接下来我们编写客户端调用代码。 LocalSessionBeanTest.jsp 在实际应用中,同时实现Remote 与Local
36、 接口是一种比较好 的做法。这样你既可以在远程访问EJB,也可以在本地访问EJB。 远程接口:Operation.java package com.foshanshop.ejb3; public interface Operation public int Addup(); 本地接口:LocalOperation.java,本地接口继承了远程接口的所有 方法 package com.foshanshop.ejb3; public interface LocalOperation extends Operation package com.foshanshop.ejb3.impl; import
37、 javax.ejb.Local; import javax.ejb.Remote; import javax.ejb.Stateless; import com.foshanshop.ejb3.LocalOperation; import com.foshanshop.ejb3.Operation; Stateless Remote (Operation.class) Local (LocalOperation.class) public class OperationBean implements Operation, LocalOperation private int total =
38、0; public int Addup() total+; return total; % InitialContext ctx = new InitialContext(); try /通过远程接口调用EJB Operation remote = (Operation) ctx.lookup(OperationBean/remote); out.println(通过远程接口调用EJB)累加的结果是:+ remote.Addup(); catch (Exception e) out.println(远程接口调用失败); out.println(=); try /通过本地接口调用EJB Loca
39、lOperation local = (LocalOperation) ctx.lookup(OperationBean/local); out.println(通过本地接口调用EJB)累加的结果是:+ local.Addup(); catch (Exception e) out.println(本地接口调用失败); % 把EJB 及客户端应用打包后发布到jboss 中,第一次执行客户端的结果如下 : 大家可能会发现在通过local 接口调用EJB 的地方,累加的结果为2。 怎么会为2,明明是第一次调用嘛,应该是1 才对呀? 这是因为Stateless Session Bean 不负责维护会话
40、状态,Stateless Session Bean 一旦实例化就被加进实例池中,各个用户都可以共用。即使 用户已经消亡,Stateless Session Bean 的生命期也不一定结束,它可能依 然存在于实例池中,供其他用户使用。如果它有自己的属性(变量),那 么这些变量就会受到所有使用它的用户影响。 stateless session bean 创建在对象池中,提供给众 多用户使用,如果Bean class 有自己的成员属性(变量 ),那么这些变量就会受到所有调用它的用户影响。在一 些应用场合中,有时我们需要每个用户都有自己的一个实 例,这个实例不受其他用户影响。就好比购物车对象,每 个用
41、户都应有自己的购物车,你不希望有人往你的购物车 里添加或拿掉商品,而有状态Bean 正好满足你的这种需 求。每个有状态Bean 在bean 实例的生命周期内都只服 务于一个用户,bean class 的成员变量可以在不同的方 法调用间维护特定于某个用户的数据。正因为在bean 实 例的生命周期内,Stateful Session Bean 保持了用户的 信息,所以叫有状态Bean。 stateless session bean 创建在对象池中,提供给众 多用户使用,如果Bean class 有自己的成员属性(变量 ),那么这些变量就会受到所有调用它的用户影响。在一 些应用场合中,有时我们需要每
42、个用户都有自己的一个实 例,这个实例不受其他用户影响。就好比购物车对象,每 个用户都应有自己的购物车,你不希望有人往你的购物车 里添加或拿掉商品,而有状态Bean 正好满足你的这种需 求。每个有状态Bean 在bean 实例的生命周期内都只服 务于一个用户,bean class 的成员变量可以在不同的方 法调用间维护特定于某个用户的数据。正因为在bean 实 例的生命周期内,Stateful Session Bean 保持了用户的 信息,所以叫有状态Bean。 package com.foshanshop.ejb3; import java.io.Serializable; import ja
43、va.util.List; public interface Cart extends Serializable public void AddBuyItem(String productName); public List getBuyItem(); SuppressWarnings(serial) Stateful Remote(Cart.class) public class CartBean implements Cart private List buyitem = new ArrayList(); public void AddBuyItem(String productName)
44、 buyitem.add(productName); public List getBuyItem() return buyitem; Stateful 注释指明这是一个有状态会话Bean,Remote 注释指定有状态 Bean 的remote 接口。 SuppressWarnings(serial) 注释屏蔽缺少serialVersionUID 定义警告。 % try InitialContext ctx = new InitialContext(); Cart cat = (Cart)session.getAttribute(cat); if(cat=null)/创建一个购物车创建一个购物
45、车 cat = (Cart) ctx.lookup(CartBean/remote); session.setAttribute(cat, cat); cat.AddBuyItem(EJB3.0实例教程); List buyitem = cat.getBuyItem(); out.println(购物车的商品列表:); for(String name : buyitem) out.println( + name+ ); catch (Exception e) out.println(e.getMessage(); % 在JSP 代码中,先试图从 session 中获取购物车的存根。如果 当前s
46、ession 不存在购物车,就创建 一个新的购物车放入session 中。后 面每执行一次页面都会添加一个相同 的商品。 需要自定义JNDI 名称时,如果EJB 在Jboss 中使用,可以使用Jboss 提供的LocalBinding 和RemoteBinding 注释,LocalBinding 注释 指定Session Bean 的Local 接口的JNDI 名称,RemoteBinding 注释指 定Session Bean 的Remote 接口的JNDI名称,如下: Remote (Operation.class) RemoteBinding (jndiBinding=foshansho
47、p/RemoteOperation) Local (LocalOperation.class) LocalBinding (jndiBinding=foshanshop/LocalOperation) public class OperationBean implements Operation, LocalOperation InitialContext ctx = new InitialContext(props); Operation operation = (Operation)ctx.lookup(foshanshop/RemoteOperation); LocalBinding 和
48、RemoteBinding 注释只是针对jboss , 如果你使用的是 weblogic10/Sun Application Server/Glassfish,你可以使用 Stateless.mappedName()设置bean 的全局JNDI 名称,如: Stateless(mappedName=OperationBeanRemote) public class OperationBean implements Operation, LocalOperation 客户端访问EJB 的代码片断如下: InitialContext ctx = new InitialContext(props);
49、 Operation operation = (Operation) ctx.lookup(OperationBeanRemote#com.foshanshop.ejb3.Operation); 由于JNDI名称与厂商有关,如果使用注释定义JNDI 名称会带来移植问题,因此建议使用ejb-jar.xml部署描 述文件进行定义,该文件必须放置在jar的META-INF目 录下 HelloWorldBean HelloWorldBean 前面我们已经对Stateless Session Bean 和stateful session bean 的生命周期有所了解。在Session bean 的生命周
50、期里,状态 变化会触发生命周期事件的发生。如从does not exist 状态进入 method-ready pool 状态会触发PostConstruct 事件。同样从 method-ready pool 状态进入does not exist 状态也会触发 PreDestroy 事件。 有些时候,你需要定制session bean 的管理过程。例如,你可 能想在创建session bean 实例的时候初始化字段变量,或在bean 实 例被销毁的时候关掉外部资源。上述这些,你都可能通过在bean 类 定义生命周期的回调方法来实现。 这些方法将会被容器在生命周期的不同阶段调用(如:创建或销 毁
51、)。通过使用下面的注释,EJB 3.0 允许你将任何方法指定为回 调方法。这不同于EJB 2.1,所有的回调方法必须实现,即使是空的 。在EJB 3.0,bean 可以有任意数量,任意名字的回调方法。 PostConstruct:当bean 对象完成实例化后,标注了 这个注释的方法会被立即调用,每个bean class 只能定 义一个PostConstruct 方法。这个注释同时适用于有 状态和无状态会话bean。 PreDestroy:标注了这个注释的方法会在容器销毁一 个无用的或者过期的bean 实例之前调用。这个注释同时 适用于有状态和无状态会话bean。 PrePassivate:当一
52、个有状态的bean 实例空闲时间过 长,就会发生钝化(passivate)。标注了这个注释的方法会 在钝化之前被调用。bean 实例被钝化后,在一段时间内 ,如果仍然没有用户对bean 实例进行操作,容器将会从 硬盘中删除它。以后,任何针对该bean 方法的调用,容 器都会抛出例外。这个注释适用于有状态会话bean。 PostActivate:当客户端再次使用已经被钝化的有状态 bean 时,EJB 容器会重新实例化一个Bean 实例,并从 硬盘中将之前的状态恢复。标注了这个注释的方法会在激 活完成时被调用。这个注释只适用于有状态会话bean。 Init:这个注释指定了有状态bean 初始化的
53、方法。它 区别于PostConstruct 注释在于:多个Init 注释方法 可以同时存在于有状态session bean 中,但每个bean 实 例只会有一个Init 注释的方法会被调用。 PostConstruct 在Init 之后被调用。 Remove:当客户端调用标注了Remove 注释的方法 时,容器将在方法执行结束后把bean 实例删除。 要处理这些生命周期事件,我们可以为 这些事件注册一个回调方法,回调方法可 以使用任何名称,但是它必须返回void, 不带参数,且不能抛出任何checked exception。事件注册的过程很简单,只需 在回调方法上面加上事件的注释就可以。 St
54、ateful Remote (LifeCycle.class) public class LifeCycleBean implements LifeCycle public String Say() try Thread.sleep(1000*10); catch (InterruptedException e) e.printStackTrace(); return 这是会话这是会话Bean生命周期应用例子生命周期应用例子; Init public void initialize () System.out.println(Init事件触发); 拦截器可以拦截Session bean 和 m
55、essage-driven bean 的方法调用或生 命周期事件。拦截器用于封装应用的公用 行为,使这些行为与业务逻辑分离,一旦 这些公用行为发生改变,而不必修改很多 业务类。拦截器可以是同一bean类中的方 法或是一个外部类。 Stateless Remote (HelloChinaRemote.class) Local(HelloChina.class) Interceptors(HelloInterceptor.class) public class HelloChinaBean implements HelloChina,HelloChinaRemote public String S
56、ayHello(String name) return name +说:你好说:你好!中国中国.; public String Myname() return 我是佛山人我是佛山人; Interceptors 注释指定一个或多个在外部类中定义的 拦截器,多个拦截器类之间用逗号分隔,上面拦截器 HelloInterceptor 对HelloChinaBean 的所有方法进行拦截。 如果你只需对某一方法进行拦截,你可以在方法上面定义 拦截器。 public class HelloInterceptor AroundInvoke public Object log(InvocationContext
57、 ctx) throws Exception System.out.println(* HelloInterceptor intercepting); long start = System.currentTimeMillis(); try if (ctx.getMethod().getName().equals(SayHello) System.out.println(* SayHello 已经被调用! * ); if (ctx.getMethod().getName().equals(Myname) System.out.println(* Myname 已经被调用! * ); retur
58、n ceed(); catch (Exception e) throw e; finally long time = System.currentTimeMillis() - start; System.out.println(用时:+ time + ms); package erceptor; public interface InvocationContext public Object getTarget( ); public Method getMethod( ); public Object getParameters( ); public void
59、setParameters(Object newArgs); public java.util.Map getContextData( ); public Object proceed( ) throws Exception; getTarget( ) 指向被调用的bean 实例 getMethod( ) 指向被拦截的业务方法 getParameters( ) 获取被拦截业务方法的参数 setParameters() 设置被拦截业务方法的参数 getContextData( ) 方法返回一个Map 对象,它在整个方法调用期间都可以被访问 到。位于同一方法调用内的不同拦截器之间可以利用它来传递上
60、下文相关的数据。 在HelloInterceptor 代码中,我们调用了 ceed()方法。如果还有其它拦截器未执行, ceed()方法内部会调用后面拦截器的 AroundInvoke 方法,直到后面的拦截器全部执行 结束,EJB 容器才会执行被拦截的业务方法。 ceed()方法必须在拦截器代码中被调用, 否则被拦截的业务方法就根本不会被执行。另外如果 我们想在被拦截的业务方法执行结束后再执行一些自 定义代码,我们可以在ceed()执行后方法返 回前加入自己的代码。 由于拦截器和被拦截的bean 方法同处于一个java 调用堆栈中,如果你
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年度普通货物运输合同范本范例
- 2024年度人力资源服务合同服务内容、员工权益及合同期限
- 2024年度保险合同的理赔范围限定
- 2024年度壁画艺术衍生品开发与销售合同
- 车载手机支架市场需求与消费特点分析
- 美容用局部皮肤喷雾市场需求与消费特点分析
- 2024年度小学操场环保施工合同
- 2024年度商标许可使用及转让合同
- 2024年度信息技术研发合同
- 2024年度新能源汽车租赁押金及还款合同
- 2024-2025学年高一上学期期中考试动员主题班会课件
- 部编人教版三年级道德与法治上册:期末测试卷(含答案)
- 卓越绩效模式标准-全国质量奖评奖标准
- 2024-2030年中国香氛香薰市场供需前景及未来销售格局分析研究报告
- (新版)碳排放管理员(技师)职业资格考试题库-上(单选题)
- 【课件】跨学科实践:探索厨房中的物态变化问题+课件人教版(2024)物理八年级上册
- 四年级上册劳动《垃圾分类宣传员》课件
- 2024-2030年中国媒体行业市场发展分析及发展趋势与投资机会研究报告
- 九年一贯制学校管理模式的实践与思考
- 2025年中考数学一轮复习:48道压轴题汇编(较难含答案)
- 2024年高中学业水平考核美术试题
评论
0/150
提交评论