基于EJB中间件技术的研究Word文档下载推荐.docx
《基于EJB中间件技术的研究Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《基于EJB中间件技术的研究Word文档下载推荐.docx(10页珍藏版)》请在冰点文库上搜索。
![基于EJB中间件技术的研究Word文档下载推荐.docx](https://file1.bingdoc.com/fileroot1/2023-5/10/d1a5d872-8c8a-44d4-9f0e-de1529f06f95/d1a5d872-8c8a-44d4-9f0e-de1529f06f951.gif)
增强应用的生命力。
1.4中间件的作用与构成
中间件是处于系统软件(操作系统和网络软件)与应用软件之间的一种软件。
有了这层处于中间的软件,就能使远距离相隔的应用软件可协同工作(互操作),这样在应用层就可以实现分布式处理。
如图1-1所示。
图1-1中间件所处的层次
作为一个中间件由两个部分组成:
1、执行环境(Executionnvironment)软件2、应用开发(ApplicationDevelopment)工具。
大概分为:
事务处理、消息、分布式三种类型的中间件。
从企业应用来说,使用中间件的好处是:
1、缩短应用开发周期2、减少项目开发风险3、应用系统质量及可维护性4、增加产品吸引力5、透明地同其他应用程序进行交互6、与运行平台提供的网络通信服务无关7、具有良好的可靠性和可用性8、具有良好的可扩展性。
2.中间件技术开发平台
2.1J2EE平台
J2EE
是企业级应用的一种规范,包含有很多方面的技术和构件:
如
Javascript、Ajax、Jsp、Servlet、JavaBean、EJB、JMS、Jdbc、JTA、SOA、远程调用RMI、事务、安全、容器、中间件、数据库以及开源的组件和框架,如Ajax框架如Jquery,DWR、展现层框架Struts、业务逻辑框架Spring、对象关系映像框架Hibernate、Ibatis等,SOA规范的重量级Websevice组件如Xfire组件、轻量级如Hessian组件,另外还有一些类似JMS和消息驱动Bean的异步消息处理框架等。
另外还可以包含如异常错误及日志处理Log4j组件及Applet等客户端组件。
2.2J2EE平台架构
(1)一个多层次的J2EE应用结构包含如下4个层次
●客户层(Client)
●Web层(Web)
●业务层(Business)
●企业信息系统层(EIS)
●业务层的业务逻辑由EJB组件来显示。
(2)J2EE组件
以上层次一般也指三层应用,因分布在三个不同位置:
客户计算机、J2EE服务器及后台的数据库或过去遗留下来的系统,如图2-1所示。
图2-1J2EE组件及其层次结构图
3.EJB技术
3.1EJB概述
EJB(EnterpriseJavaBean)是J2EE体系结构的核心组件。
他主要为J2EE应用程序提供业务逻辑,并与其他服务器端J2EE组件交互。
业务逻辑以及与其他服务器端J2EE组件交互的特征取决于J2EE应用程序。
EJB2.1规范将它定义为一个基于组件的分别式计算体系结构,它是用Java开发的并安装在一个应用程序服务器中的组件,提供了命名、安全性、事务性以及其他企业级服务。
这些被安装的组件能按一种分布式形式通过网络来实现。
EJB是支持网络的组件,可以在应用服务器的J2EE环境中开发安全、可伸缩、事务性的多用户组件,它运行在EJB容器中。
他的常见特征有:
·
它们从属于一个为他们提供生命周期的容器。
EJB实例由容器创建并维护。
通过编辑一个基于XML的部署描述符可以在部署时自定义她们。
系统级服务与企业bean分开描述。
客户机不能直接访问一个企业bean;
容器环境为客户机访问的媒介。
企业bean被设计为可移植的,可以在不同厂商提供的EJB服务器之间进行植。
EJB的首要目的是使得开发者专注于业务逻辑,而不必担心他们的应用程序所需的事务、安全以及持久性等底层细节。
EJB是一个用于分布式业务应用的标准服务端组件模型。
采用EJB架构编写的应用是可伸的、事务性的、多用户安全的。
可以一次编写这些应用,然后部署在任何支持EJB规范的服务器平台,如jboss、weblogic等。
3.2EJB容器
EJB需要运行在EJB容器,每个JavaEE应用服务器都含有EJB容器和Web容器,所以既可以运行EJB,也可以运行Web应用。
目前支持EJB3.0的应用服务器有Jboss(4.2.x以上版本)、Glassfish、Weblogic(10以上版本)、SunApplicationServer(9.0以上版本)、OracleApplicationServer(10g以上版本)和我们国内的apusic应用服务器。
JBoss是一个开源的J2EE应用服务器,可以在该容器下部署和运行EJB组件。
早期的JBoss版本只包含EJB容器,而不包含Servlet容器,因此需要把JBoss于Tomcat集成,二者协同工作,才能构成完整的J2EE应用服务器。
新版本的JBoss同时提供了Servlet容器和EJB容器,因此既能运行JavaWeb应用,又能运行EJB组件。
3.3JNDI
JNDI是自JDK1.3版本开始就绑定的标准JavaAPI。
它为各种现有的命名和目录服务提供了通用接口:
DNS、LDAP、活动目录(ActiveDirectory)、RMI注册器、COS注册器、NIS及文件系统。
在结构上,JNDI由两部分组成:
客户API和服务提供商接口(ServiceProviderIntergace,SPI),应用程序通过客户API访问命名和目录服务;
服务提供商接口用于供厂商创建命名和目录服务的JNDI实现。
可以简单的把JNDI理解为一种将对象和名字绑定的技术,对象工厂(此处指JBoss容器)负责生产出对象,这些对象都有唯一的名字绑定。
外部程序可以通过名字来获得对象的引用。
在javax.naming包中提供了Context接口,该接口提供了通过名字检索对象的方法。
Objectlookup(Stringname)返回与指定的名字绑定的对象。
3.4EJB组件的种类
(1)会话Bean
SessionBean是实现业务逻辑的地方。
根据是否可以维护会话状态,SessionBean分为有状态bean和无状态bean。
有状态bean可以维护会话状态,无状态bean不维护会话状态。
要维护会话状态,意味着EJB容器要为每个用户创建一个bean实例,并通过该实例保存着与用户的会话状态。
不维护会话状态,意味着一个bean实例不需要保存与某个用户的会话状态,这时一个bean实例可以为多个用户服务。
由于无状态会话Bean不维护会话状态,意味着一个bean实例可以为多个用户服务。
因此EJB容器使用实例池化技术管理无状态会话Bean。
简单的说就是:
当无状态会话Bean部署到应用服务器时,EJB容器会为它预先创建一些bean实例放在对象池。
当有用户访问EJB方法时,EJB容器会从对象池中取出一个实例为之服务,服务完了就回到对象池。
当下一个用户再访问EJB方法时,EJB容器有可能再次把该实例取出来为之服务。
正因如此,无状态会话Bean只需要少量的实例就可以为成百上千的用户服务,大大提高了系统性能。
由于无状态会话Bean能够支持多个用户,并且通常在EJB容器中共享,可以为需要大量客户的应用提供更好的扩充能力。
无状态会话Bean比有状态会话Bean更具性能优势,在条件允许的情况下开发人员应该首先考虑使用无状态会话Bean。
statelesssessionbean创建在对象池中,提供给众多用户使用,如果Beanclass有自己的成员属性(变量),那么这些变量就会受到所有调用它的用户影响。
在一些应用场合中,有时我们需要每个用户都有自己的一个实例,这个实例不受其他用户影响。
就好比购物车对象,每个用户都应有自己的购物车,你不希望有人往你的购物车里添加或拿掉商品,而有状态Bean正好满足你的这种需求。
每个有状态Bean在bean实例的生命周期内都只服务于一个用户,beanclass的成员变量可以在不同的方法调用间维护特定于某个用户的数据。
正因为在bean实例的生命周期内,StatefulSessionBean保持了用户的信息,所以叫有状态Bean。
(2)实体Bean
一般地,实体代表关系型数据库中的一行记录。
尽管这不是它的唯一目的,但这通常是最常用的。
EJB体系结构提供了用户并发访问,可以通过适当的同步来访问相同的EJB实例。
容器工作时,由于在服务器上资源有限,对于很少使用的实例,需要将它们放回bean池,使得其他客户机可以使用它们。
在企业级应用程序的开发中,采用实体bean有一定的系统开销,我们之所以采用实体bean,主要考虑到,EJB是一种重量级的体系结构,设计成支持分布式事务,而且支持多个用户对共享数据的并发访问。
实体Bean代表数据库或另外一个企业应用系统中的数据对象,如代表数据库的一行记录。
由于实体Bean是底层数据库记录的映象,和数据库记录保持同步,所以它是持久的,其状态不依赖于服务器而存在,允许共享访问。
按持久性划分,实体Bean分为Bean管理持久化和容器管理持久化两种。
前者指有Bean开发者自己管理Bean和它所代表的数据库记录同步;
后者指由容器自动管理Bean和它所代表的数据库记录同步,不需要开发者编写SQL语句。
(3)消息驱动Bean
消息驱动bean,对于EJB体系结构是最新的,它从2.0版本才开始引入。
为什么要引入消息驱动bean没有使用它之前,大多数JMS消息使用者作为运行在容器之外的简单Java程序而建立的。
尽管使用JMS服务,可以解决同步问题,但最大的问题是可伸缩性。
如果消息负载开始增加,必须在容器之外启动多个Java客户机应用程序来担当多个消息使用者,或者仅仅依靠单个消息消费者来处理所有传入消息。
这可能阻塞目的地,并且如果负载太大.可能会丢失一些消息。
在EJB2.0中引入消息驱动bean。
通过允许容器去聚合并且管理消息驱动bean实例,以此来提供传入JMS消息的并发处理。
消息驱动bean用来异步地处理Java消息服务的消息,表现的有两个关键地方。
第一,消息驱动bean不直接显示给客户机。
第二,消息驱动bean是完全由容器管理,不允许客户机通过创建和删除方法来管理它们的生命周期。
一般地,我们要使用消息驱动bean是在通过使用被发送到某个JMS目的地的JMS消息,消息驱动bean来执行一些商业逻辑。
Java消息服务(JavaMessageService,简称JMS)是用于访问企业消息系统的开发商中立的API。
企业消息系统可以协助应用软件通过网络进行消息交互。
JMS在其中扮演的角色与JDBC很相似,正如JDBC提供了一套用于访问各种不同关系数据库的公共API,JMS也提供了独立于特定厂商的企业消息系统访问方式。
使用JMS的应用程序被称为JMS客户端,处理消息路由与传递的消息系统被称为JMSProvider,而JMS应用则是由多个JMS客户端和一个JMSProvider构成的业务系统。
发送消息的JMS客户端被称为生产者(producer),而接收消息的JMS客户端则被称为消费者(consumer)。
同一JMS客户端既可以是生产者也可以是消费者。
3.5EJB的调用过程
①客户端程序使用lookup方法查找JNDI
②EJB服务器的JDNI服务根据事先登录的信息匹配lookup查询内容,生成Home实例
③客户端得到对Home实例的引用
④客户端调用Home.create方法
⑤创建相对应的Bean实例,调用Bean的ejbCreate方法
⑥生成相对应的RemoteOjbect实例
⑦客户端得到对RemoteOjbect实例的引用
⑧客户端掉用业务逻辑方法
客户端与服务器端的通信使用RMI-IIOP通信协议。
客户端在调用EJB组件时,需要知道EJB组件的位置(包括IP,端口,名称),才能得到对EJB组件对象的引用。
JNDI是J2EE提供的一套JavaAPI,是JavaNamingandDirectoryInterface的略称,提供根据名称查找对象的服务。
EJB利用JNDI来解决名称问题。
JNDI有ServiceProvider的概念,Provider可以选择LDAP或者RMI。
4.EJB开发
以会话bean为例说明EJB开发应用的过程。
要开发一个SessionBean,我们需要定义接口和Beanclass。
其中接口分为远程(remote)和本地(local)接口。
在EJB3.0中,不要求你同时实现remote和local接口,但实现两者是比较好的做法。
远程接口(remoteinterface):
定义了sessionbean的业务方法,这些方法可以被来自EJB容器之外的应用访问到。
本地接口(localinterface):
同样定义了sessionbean的业务方法,这些方法可以被同处于EJB容器内的其它应用使用。
因为local接口允许bean之间直接通过内存交互,没有分布式对象协议的开销,从而改善了性能。
Bean类(beanclass):
beanclass包含了业务逻辑,它必须具备一个远程或本地接口。
在Bean类,我们应该实现接口的业务方法,尽管这并不是必须的,但我们没理由不这样做。
开发步骤:
1 定义一个包含业务方法的接口。
这个接口不需要包含任何注释,它是一个普通的java接口。
调用EJB的客户端使用这个接口引用从EJB容器返回的存根(stub)。
编写Beanclass,Bean类推荐的命名方式是:
接口+Bean,如:
HelloWorldBean。
2 在Bean类上面注释@Stateless或者@Stateful和@Remote、@Local。
@Stateless注释指明这是一个无状态会话Bean,@Stateful注释指明这个是一个有状态会话bean,无状态会话bean与有状态会话bean只能选一个。
@Local注释声明接口是本地接口,@Remote注释指定这个Bean的remote接口。
Bean类可以具有多个remote接口,每个接口之间用逗号分隔,如:
@Remote({HelloWorld.class,Hello.class,World.class})。
如果你只有一个接口,你可以省略大括号,可以写成这样:
@Remote(HelloWorld.class)。
当@Local和@Remote注释都不存在时,容器会将Beanclass实现的接口默认为Local接口。
如果EJB与客户端部署在同一个应用服务器,采用Local接口访问EJB优于Remote接口。
因为通过Remote接口访问EJB需要在tcp/ip协议基础上转换和解释CorbaIIOP协议消息,在调用EJB的这一过程中存在对象序列化,协议解释、tcp/ip通信等开销。
而通过Local接口访问EJB是在内存中与bean彼此交互的,没有了分布式对象协议的开销,大大改善了性能。
3 把EJB发布到Jboss中。
在发布前我们需要把它打成Jar包。
当EJB发布成功后,Jboss容器会为它生成一个全局JNDI名称,我们可以利用这一点进一步判断EJB发布是否成功。
如果把EJB作为模块打包进后缀为*.ear的JAVAEE企业应用文件,默认的全局JNDI名称是
本地接口:
EAR-FILE-BASE-NAME/EJB-CLASS-NAME/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-NAME/remote
把HelloWorld应用打包成HelloWorld.jar文件,它的远程接口的JNDI名称是:
HelloWorldBean/remote。
注意:
EJB-CLASS-NAME是不带包名的。
如果你通过@Stateless.name()、@Stateful.name()及其等价的XML指定了EJB名称,那么上面的EJB-CLASS-NAME应该换为EJB名称,此时的JNDI名称格式如:
EJB名称/remote、EAR文件名/EJB名称/remote。
4 开发客户端程序,访问EJB,也就是查找JNDI。
在进行JNDI查找前,我们必须设置应用服务器的上下文信息,主要是设置JNDI驱动的类名(java.naming.factory.initial)和命名服务提供者的URL(java.naming.provider.url)。
java.naming.factory.initial或Context.INITIAL_CONTEXT_FACTORY:
环境属性名,用于指定InitialContext工厂,它类似于JDBC指定数据库驱动类。
java.naming.provider.url或Context.PROVIDER_URL:
环境属性名,包含提供命名服务的主机地址和端口号。
它类似于JDBC指定数据库的连接URL。
连接到JbossNS的URL格式为:
jnp:
//host:
port,该URL的“jnp:
”部分是指使用的协议,JBoss使用的是基于Socket/RMI的协议。
host为主机的地址,port为JNDI服务的端口。
除了host之外,其他部分都是可以不写的。
除了上述两个环境属性外,还有两个环境属性是我们经常使用到的:
java.naming.security.principal(或Context.SECURITY_PRINCIPAL)和java.naming.security.credentials(或Context.SECURITY_CREDENTIALS),这两个环境属性用于指定用户标识(如用户名)及凭证(如密码),当EJB使用了安全服务时,你必须提供这两个属性。
它类似于JDBC指定连接到数据库的用户名及密码。
如果客户端运行在应用服务器内,我们不需要为InitialContext设置应用服务器的上下文信息,也不建议设置。
因为应用服务器启动时会把JNDI驱动类等上下文信息添加进系统属性,创建InitialContext对象时如果没有指定Properties参数,InitialContext内部会调用System.getProperty()方法从系统属性里获取必要的上下文信息。
对本例子而言,你可以省略传入props参数。
在实际应用中,如果给InitialContext设置了参数,反而会带来不可移植的问题。
创建InitialContext对象时如果没有指定Properties参数,InitialContext还会在classpath下寻找jndi.properties文件,并从该文件中加载应用服务器的上下文信息。
这样避免了硬编码为InitialContext设置Properties参数。
jndi.properties的配置如下:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=localhost:
1099
java.naming.factory.url.pkgs=org.jboss.naming:
org.jnp.interfaces
当InitialContext初始化后,我们使用EJB的Jndi名称通过lookup()方法查找EJB。
lookup()方法返回一个存根对象,该存根实现了一个接口。
它负责将方法调用路由到应用服务器,应用服务器再把方法调用请求路由到该实例。
开发实例:
1 服务器端开发,接口HelloWorld与实现类HelloWorldBean
publicinterfaceHelloWorld{
publicStringSayHello(Stringname);
}
@Stateless
@Remote({HelloWorld.class})
publicclassHelloWorldBeanimplementsHelloWorld{
@Override
publicStringSayHello(Stringname){
//TODOAuto-generatedmethodstub
returnname+"
说:
你好!
EJB测试。
"
;
}
2 客户端开发,jsp页面
<
%@pagecontentType="
text/html;
charset=UTF-8"
%>
%@pageimport="
ejb.server.HelloWorld,javax.naming.*,java.util.Properties"
%
Propertiesprops=newProperties();
props.setProperty("
java.naming.factory.initial"
"
org.jnp.interfaces.NamingContextFactory"
);
java.naming.provider.url"
"
localhost:
1099"
try{
InitialContextctx=newInitialContext(props);
HelloWorldhelloworld=(HelloWorld)ctx.lookup("
HelloWorldBean/remote"
out.println(helloworld.SayHello("
李培杰"
));