J2EE应用部署(一):基础篇
提纲:
一、基础知识
1.1 J2EE应用的构成
1.2 封装和部署操作的任务
1.3 不能封装到EAR文件的组件
二、类装载模式
2.1 在EJB 2.0之前
2.2 在EJB 2.0之后
===================================
一、基础知识
1.1 J2EE应用的构成
J2EE应用由以下两种资源构成:
一个或者多个J2EE组件
一个J2EE应用部署描述器(Deployment Descriptor)
当多个异种的J2EE组件需要相互调用时,我们必须创建一个J2EE应用。在创建J2EE应用的过程中,有许多事情必须考虑,其中包括:
有哪些类型的组件可以封装到J2EE应用里?
创建J2EE应用的过程中,人们担负的各种职责。
当前J2EE封装技术的局限之处。
为满足J2EE组件交互的需要,不同的供应商所采取的类装载策略。
J2EE规范区分了两类资源:可以在容器之内运行的资源,可以封装到EAR文件内的资源。EAR是Enterprise Application ARchive的缩写,EAR文件用来把一个或者多个J2EE组件封装到单个模块里面,以便一起部署并装入到服务器上。
J2EE规范阐明了运行时容器和部署模块之间的区别。运行时容器是请求级的截取机制,为系统内的组件提供一种基础服务。部署模块是一种为那些最终将在运行时容器内执行的组件提供的封装结构。下图描述了J2EE容器的结构:
其中:
EJB容器
EJB容器用来容纳业务逻辑,并为业务逻辑截取请求。EJB容器支持EJB访问JMS、JAAS、JTA、JavaMail、JAXP、JDBC和连接器(Connector)。
Web容器
Web容器截取通过HTTP、FTP、SMTP或其他协议发送的请求。Web应用容器为Servlet和JSP页面提供的资源与EJB容器提供的资源相同。
应用客户端容器
客户端应用是独立的Java应用,它们在远程的独立JVM上运行(与Web容器和EJB容器所运行的JVM不同)。应用客户端容器为这些应用截取请求。
运行在应用客户端容器上的程序非常类似于带有main()方法的Java程序,不过,程序不再由JVM控制,而是由一个容器(也就是应用客户端容器)控制。
在应用客户端容器内运行的程序能够访问远程应用服务器上的JAXP、JDBC、JMS和JAAS资源。
Applet容器
Applet容器是一个特殊的容器,它为在浏览器内运行的Java程序截取请求。Applet容器不提供任何对其他资源(比如JDBC或JMS)的访 问。在Applet容器内运行的Applet必须自己直接向应用服务器请求资源(而不是把请求发送给容器,然后由容器发送请求给应用服务器)。
对于Applet如何与EJB容器进行通信,EJB规范没有作出任何规定,但J2EE规范有这方面的规定。对于那些想要直接使用EJB的 Applet,J2EE规范要求它们使用HTTP隧道。许多应用服务器提供某种形式的HTTP隧道,支持Applet直接使用EJB。
可以封装到J2EE EAR文件里面的组件与包含容器的组件之间不存在直接的关联。J2EE没有规定EAR文件至少必须包含哪些内容,EAR文件可以由任意数量的以下组件构成:
EJB应用JAR文件
EJB应用JAR文件包含一个或者多个EJB组件。
Web应用WAR文件
一个WAR文件包含一个Web应用。EAR文件可以包含多个Web应用,EAR文件中的每个Web应用必须有一个唯一的部署上下文。EAR文件的部署机制允许指定这类不同的上下文。
应用客户端JAR文件
应用客户端JAR文件包含一个准备在应用客户端容器内运行的独立Java应用,还包含一个专用的部署描述器,其构成方式和EJB JAR文件的构成方式相似。
应用客户端JAR文件除了包含运行独立客户程序所需要的类之外,还包含访问JDBC、JMS、JAXP、JAAS和EJB客户所需要的客户端库。
资源适配器RAR文件
资源适配器RAR文件包含了实现企业信息系统JCA(Java Connector Architecture)资源适配器所需要的Java类和本地库。
资源适配器不在容器内执行。相反,它们应该作为应用服务器和外部企业信息系统之间的桥接软件执行。
这些组件都在J2EE EAR文件之外分别地开发和打包,且分别拥有自己的部署描述器。然后,J2EE EAR文件通过定制的部署描述器,把一个或者多个这种组件装配成一个统一的包。
1.2 封装和部署操作的任务
在EJB、Web应用或其他组件的构造、部署和使用过程中,不同的人担负着不同的职责。J2EE规范为开发者在创建企业应用过程中的职责定义了范围广泛 的平台角色(Platform Role)。尽管角色的数量众多,但它们不外乎是一种为了更好地规划和运行一个应用而设计的逻辑划分,单独的个人、小组或组织很可能扮演多个角色。在构 造、部署使用EAR文件的过程中,常见的角色包括:
J2EE产品提供者
负责实现J2EE平台,包括在规范中定义的所有J2EE API和其他功能。比如,J2EE应用服务器的供应商。
应用组件提供者
负责提供J2EE组件,例如EJB应用或Web应用。J2EE规范中的许多角色都具有应用组件提供者的特征,比如文档编写者、JSP页面编写者、资源适配器开发者等。
应用组装者
负责把一个或者多个J2EE组件打包成EAR文件,构造出J2EE应用。应用组装者还要负责创建J2EE应用部署描述器,说明应用依赖的各种外部资源,比如类库、安全角色等。通常,应用组装者要用到J2EE产品提供者和工具提供者提供的工具。
工具提供者
提供自动化J2EE应用创建、打包、部署过程的工具,例如为EAR文件自动生成部署描述器的工具,自动创建EAR文件的工具。
部署者
负责把Web应用和EJB应用部署到服务器环境上。部署者不负责部署资源适配器包和应用客户端包,但可能要负责为这些组件进行额外的配置。这些组件虽然 被打包成为J2EE EAR文件的一部分,部署企业应用时却不必考虑。它们是J2EE应用的一部分,但不必象Web应用和EJB容器那样经过一个“激活”过程。资源适配器包是 置入合法JCA实现的简单库,虽然它们被打包进J2EE EAR文件,但它们不在J2EE容器环境下运行。因此,由于资源适配器包不包含J2EE容器,它们的激活不需要J2EE部署者的特别干预。应用客户端程序 在J2EE容器的环境下运行,但它们不部署到应用服务器上。客户端程序独立运行,部署者不负责为这些程序配置容器环境。
系统管理员
负责为应用服务器和J2EE应用配置网络和运行环境,负责监视和维护J2EE应用的运行。
在本文的讨论过程中,我们主要的角色是应用组装者和部署者。
1.3 不能封装到EAR文件的组件
大多数基于Web的J2EE应用只由Web和EJB应用构成,EAR文件能够满足封装应用的基本需求。然而,EAR文件缺乏封装复杂J2EE应用的能力,比如,J2EE经常要用到下面这类组件,但它们无法在EAR文件中声明:
JDBC DataSource对象。
JMS ConnectionFactory和Destination对象。
JMX(Java Management Extension)的MBean。
在应用服务器之内运行的一些JMS消费者,例如作为ServerSession一部分运行的MessageConsumer。
当应用被部署或卸载时触发运行的一些类(这些类是供应商提供的私有扩展,没有在J2EE规范中定义,但供应商一般都提供它们)。
当前,这些组件必须由系统管理员通过专用管理接口手工配置和部署。随着时间的推移,这些组件的应用也将日益增加,为了支持应用的整体移植性,让EAR文件支持这些组件的封装也变得日益重要。
二、类装载模式
当一个类被引用时,Java虚拟机(JVM)必须装入被引用的类。JVM利用一个标准的类装入机制把类装入内存,这个从源文件装入Java类的机制称 为类装载器。Java类可以从磁盘、网络或其他媒体装入,它们可以驻留在任何地方。多个类装载器可以按照父-子关系链接在一起,形成一种层次结构。由子类 装载器装入的类能够看到(能够使用)由任意父类装载器装入的类;由父类装载器装入的类不能看到由任意子类装载器装入的类。类装载器、EAR文件与应用部署 有着重要关系,因为应用服务器可能采用专用的类装载器部署应用模块。
如果在一个系统中,Web应用需要访问某个EJB,它就必须能够装入它所需要的那些类。由于这意味着不同模块之间的依赖关系,为了解决依赖问题,应用服务器必须为EAR类装载器考虑不同的结构方案。
独立的应用程序部署在它自己的类装载器中。这意味着,如果分别地部署一个Web应用和一个EJB应用,每个应用的类将分别装入各自的、级别相同的类装入 器,Web应用内的类不能看到另一个类装载器装入的类。如果Web应用想要使用那些分开部署的EJB,就会出现问题。
在EAR文件出现之 前,许多开发者先部署EJB,然后以Web应用WEB-INF\lib目录一部分的形式,再次封装同一EJB JAR文件。这样,同一类文件必须放入两个不同的地方,才能让应用正常地运行。显然,这是一种应当避免的情形。EAR文件的引入就是为了解决这个问题。 EAR文件不仅是一种方便的封装格式,而且它还提供了一种特殊的类装载模式,允许EAR文件内的应用访问其他应用的类。
J2EE 1.3规范没有具体规定EAR类装载器应该如何运作。在决定类装入方式时,应用服务器供应商有着很大的自由。实现EAR类装载器之前,供应商必须决定:
EAR文件中所有应用的所有类由单一的类装载器装入,还是不同应用的文件由不同的类装载器装入?
在EAR文件中的不同应用之间,是否存在类装载器的父-子关系?例如,如果两个EJB应用依赖于log4j.jar,那么,是否应该由父类装载器装入log4j.jar,由子类装载器装入两个EJB应用,从而维持适当的可见性关系.
J2EE应用部署(二)
目录:
一、配置J2EE包
1.1 企业应用的开发过程
1.2 J2EE应用包的结构
1.3 EAR部署描述器
二、一个简单的实例
2.1 组件
2.2 装配应用
2.3 部署和运行应用
三、可选的应用部署描述器标记
======================================
一、配置J2EE包
在上一篇文章中,我们了解了J2EE应用封装和部署的一些基本知识,包括类装载器的不同角色和行为。接下来就可以配置和部署企业应用。为此,我们必须了解创建EAR文件的过程,以及应用部署描述器的内容。
1.1 企业应用的开发过程
构造一个企业应用的过程可以归纳为:
构造各个组件,包括EJB、JSP页面、Servlet和资源适配器等。
把 这些组件打包成JAR文件格式的J2EE模块,同时提供J2EE模块部署描述器。J2EE模块是一种具有相同类型的一个或者多个J2EE组件的集合,也就 是说,一个EJB模块可以包含一个以上的EJB,一个Web应用模块可以包含多个JSP页面和Servlet,一个资源适配器包可以包含多个资源适配器。
结 合一个或者多个J2EE模块创建EAR文件,同时提供企业应用部署描述器,构造出J2EE应用。最简单的J2EE应用只包含一个J2EE模块,稍微复杂一 点的J2EE应用可以由多个J2EE模块构成,更复杂的J2EE应用可以包含多个J2EE模块、模块里面包含的类所用到的依赖库。J2EE应用还可以包含 描述部署过程的帮助文件和其他文档。
把 J2EE应用部署到J2EE平台上。安装J2EE应用,然后把它与应用服务器提供的基础设施整合。在J2EE应用部署过程中,每一个J2EE模块按照该类 模块的部署要求分别部署,每一个组件被部署到适合该组件类型的合适容器。例如,假设有一个 my.ear文件,它包含my.jar和my.war。部署应用时,应用服务器的部署工具将把my.ear文件拷贝到应用服务器;接着,应用服务器的部署 机制将提取出my.jar和my.war模块,按照当前平台的类装载要求分别部署这两个模块。如果这两个模块都部署成功,则整个J2EE应用部署成功。
J2EE企业应用开发和部署过程可以图示如下:
组 件被封装成J2EE模块时带有一个部署描述器,J2EE模块可以通过部署工具创建。部署工具还可以用来部署和“反部署”独立的J2EE模块,用来把一个或 者多个J2EE模块和另外的部署描述器封装成J2EE应用,用来把额外的内容加入J2EE应用或从J2EE应用删除某些内容,或者把整个应用部署到应用服 务器上。
1.2 J2EE应用包的结构
J2EE企业应用包的结构很简单,它由一个或多个J2EE模块以及一个META-INF\目录下名为application.xml的部署描述器构成。文件用JAR格式打包,存储在扩展名为.ear的文件中。EAR文件可以包含依赖库,但这是可选的。EAR文件的一般结构是:
EJB .jar文件 Web应用.war文件 资源适配器.rar文件 应用客户端.jar文件依赖库.jar文件 META-INF\ application.xml
下面是一个EAR文件的例子,它包含一个EJB模块、一个Web应用模块,不包含依赖库:
MyFirstEJB.jar MyFirstWeb.war META-INF\ application.xml
保存在EAR文件中的J2EE模块不一定要在根目录之下。例如,假设一个EAR文件包含一个EJB模块、一个资源适配器包,它的结构可以如下:
ejbs\ MySecondEJB.jar resources\ MyLegacyAdapter.rar META-INF\ application.xml
最后,下面是一个包含许多组件和依赖库的EAR文件:
ejbs\ MyThirdEJB.jar MyFourthEJB.jar resources\ MyLegacyAdapter.rar web\ MyWebApp1.war MyWebApp2.war lib\ Myxmlx.jar Mycommon.jar META-INF\ application.xml
EAR文件可以用部署工具创建,或者也可以改用JDK提供的jar工具创建。创建步骤为:
创建一个用来容纳EAR文件内容的临时目录。
把所有J2EE模块放入临时目录,创建META-INF\目录。
在META-INF\目录下创建application.xml部署描述器。
完成上述步骤之后,进入临时目录,运行jar工具创建EAR文件。
下面是一个运行jar工具的例子,它对前面例子进行打包:
jar cvf MyApplication.ear ejbs resources web lib META-INF
创建好EAR文件之后,我们就可以把J2EE应用部署到应用服务器上。
1.3 EAR部署描述器
理想情况下,我们用图形界面的工具编写application.xml文件。然而,有时我们必须手工构造或维护application.xml文件,因此理解application.xml文件用到的标记很重要。
application.xml部署描述器并不复杂,不需要很多标记就可以构造出一个合法的描述器。部署描述器的DTD定义的标记包括:
所有合法的J2EE应用描述器必须包含如下DOCTYPE声明:
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application
1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
配置一个简单的application.xml部署描述器只需如下几步:
用标记声明一个企业应用。标记可以包含、和标记,供部署工具提供有关应用的描述信息使用。这些标记的内容和EJB、Web应用、资源适配器部署描述器内的同一标记的内容相同。
企 业应用内的每一个模块必须有一个相应的标记描述模块。EJB用标记描述,Web应用用标记描述,资源适配器用标记描述,应用客户端程序用标记描述。除了标 记之外,其他标记的内容都是指定EAR文件内包含J2EE模块的文件的相对URI,该URI必须相对于EAR文件的根。
如 果企业应用包含一个 Web应用J2EE模块,则必须提供一个标记和一个标记。标记是一个相对URI,指定EAR文件内包含J2EE模块的文件。这个URI和、、标记的URI 同属一类。标记指定Web应用将在其下运行的上下文的名字。所有针对该Web应用内JSP页面和Servlet的请求都必须加上该上下文名字作为前缀。例 如,如果部署Web应用时指定了:
<context-root>web1</context-root>
则所有对JSP页面和Servlet的请求必须是如下形式:
http://主机:端口/web1/......
在EAR文件内封装的每一个Web应用都要有一个唯一的值,任何两个Web应用不能有相同的值。如果EAR文件只包含一个Web应用,的值可以是空字符串。
二、一个简单的实例
在大多数使用EAR文件的情形中,企业应用包含一个EJB模块、一个Web应用模块,Web应用要用到EJB模块里面的EJB组件。下面的例子就属于这种情况,EJB和Web应用不需要任何依赖库。下面我们来看看构造这个例子的具体过程。
2.1 组件
在 这个例子中,一个Servlet在无状态会话EJB的远程接口上调用invoke()方法,Servlet和EJB输出一些文字信息表明程序已经成功执 行。如果控制台出现异常报告,它很可能意味着组件封装存在问题。本例的所有EJB源文件都属于test包,Servlet属于未命名的包。本例用到的 Java文件包括:
MyEnterpriseServlet.java:Servlet的实现类,执行对EJB的调用
MyEnterprise.java:EJB的远程接口。
MyEnterpriseHome.java:EJB的Home接口。
MyEnterpriseBean.java::EJB的实现类。
MyEnterpriseBean.java的实现代码是:
package test;
import javax.ejb.*;
public class MyEnterpriseBean implements SessionBean {;
private InitialContext ctx;
public void ejbCreate() {;};
public void ejbRemove() {;};
public void ejbActivate() {;};
public void ejbPassivate() {;};
public void setSessionContext(SessionContext c) {;};
public void invoke() {;
System.out.println("正在执行EJB.");
};
};
MyEnterpriseServlet.java Servlet的实现代码是:
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.naming.*;
public class MyEnterpriseServlet extends HttpServlet {;
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException{;
res.setContentType("text/html;charset=GB2312");
PrintWriter out = res.getWriter();
try {;
System.out.println("正在服务器上运行Servlet");
InitialContext ctx = new InitialContext();
test.MyEnterpriseHome eHome = (test.MyEnterpriseHome)
ctx.lookup("MyEnterpriseEJB");
test.MyEnterprise e = eHome.create();
e.invoke();
}; catch(Exception e) {;
out.println("异常: " + e);
System.out.println("异常: " + e);
};
out.println("<html><head><title>测试</title></head>");
out.println("<body>");
out.println("<h1>检查控制台确信EJB已经被调用</h1>");
out.println("</body></html>");
};
};
编 写好EJB和相关的部署描述器(此处不列出)之后,接下来要把EJB封装成MyEnterpriseBean.jar文件。在JNDI名称空间配置中, EJB绑定到MyEnterpriseEJB。编写好Servlet代码和相关的部署描述器(此处也不列出)之后,Servlet应该封装成 MyWebApp.war文件。
构造好各个组件之后,接下来应该编写企业应用部署描述器。我们必须把EJB和Web应用注册为企业应用的模块,还要让Web应用的组件在/web/上下文之下执行。这样,本例的application.xml文件应该为:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC ´-//Sun Microsystems, Inc.//DTD J2EE Application
1.3//EN´ ´http://java.sun.com/dtd/application_1_3.dtd´>
<application>
<display-name>Enterprise Application</display-name>
<module>
<ejb>MyEnterpriseBean.jar
</module>
<module>
<web>
<web-uri>MyWebApp.war</web-uri>
<context-root>web</context-root>
</web>
</module>
</application>
编写好application.xml部署描述器之后,企业应用的目录将包括:
MyEnterpriseBean.jar MyWebApp.war META-INF\ application.xml
用jar工具创建名为MyEnterprise.ear的EAR文件,控制台命令如下:
jar cvf MyEnterprise.ear MyEnterpriseBean.jar MyWebApp.war META-INF
值 得一提的是,如果使用J2EE参考实现(Reference Implementation)提供的deploytool,我们不必手工编写ejb-jar.xml、web.xml和application.xml 部署描述器,这些文件由deploytool自动生成。在本例的企业应用中,application.xml就是自动生成的。
2.3 部署和运行应用
构造好EAR文件之后,接下来该部署它了。记住,具体的部署操作和平台有关,不同的供应商提供了不同的部署工具。例如,J2EE的deploytool能够把企业应用部署到J2EE参考实现上。
成功地部署好企业应用之后,接下来就可以调用Servlet了。由于该企业应用上下文的根是/web,Servlet作为它的一部分调用。为此,我们在浏览器中输入的地址应该是如下形式:
http://主机:端口/web/myenterpriseservlet/
三、可选的应用部署描述器标记
在某些情形下,有两个可选的部署描述器标记可供使用,它们是和标记。
是 的子标记,它的值是一个为模块提供的从EAR文件的根开始的URI,指向另一个部署描述器文件。这个文件的命名不必和它在J2EE模块里面时一样。例如, 所有EJB模块的部署描述器必须命名为ejb-jar.xml,但如果标记的值指向一个EJB模块的可选部署描述器,文件就可以取ejb-jar.xml 以外的名字。
标记中指定的部署 描述器文件将覆盖J2EE模块里面包含的描述器,。标记可以用来引用部署描述器的外部版本,当部署者想要使用的部署描述器与包含在EJB、Web应用、资 源适配器或者应用客户端模块内的描述器不同时,就可以使用这个标记。如果不指定标记的值,部署工具将使用EAR 文件里面JAR、WAR或RAR文件中提供的值。例如,要为Web应用指定一个外部的可选部署描述器,假设该描述器在EAR文件的根下面,我们指定:
<module>
<web>
<web-uri>web.war</web-uri>
<context-root>web</context-root>
</web>
<alt-dd>external-web.xml</alt-dd>
</module>
标记用来指定应用级的安全角色,这个安全角色将用于EAR文件包含的所有J2EE模块。如果EAR文件包含多个EJB模块或多个Web应用模块,这些模块都 可以有自己的安全角色定义。部署者的责任之一是确保所有J2EE模块中包含的所有安全角色都有一个唯一的名字,而且对于应用整体来说具有实际意义。安全角 色可以从J2EE模块级“拉出”到企业应用级,加入到标记。也就是说,如果某个J2EE模块中存在一个重复的安全角色值,该值可以删除,只需在企业应用级 提供即可。
标记需要一个子标记指定安全角色的名称。下面是一个配置标记的例子:
<security-role>
<description>
Security role of administrator
</description>
<role-name>Administrator</role-name>
</security-role>
J2EE应用部署(三):高级篇
提纲:
一、模块次序问题
二、依靠库的问题
2.1 解决方案之一
2.2 解决方案之二
2.3 依靠库应用实例
=========================================================
正文:
在前面两篇文章中,我们了解了J2EE应用封装和部署的基本概念和实践操作,下面我们来看看几个可能碰到的问题。
一、模块次序问题
J2EE规范没有对EAR文件内的J2EE模块应该如何部署作出任何规定。非凡地,J2EE规范没有明确规定部署模块的次序。假如一个模块中的某个组件要用到另一个待部署模块的组件,它可能会带来问题。
因此,必须注重大多数应用服务器以如下步骤部署EAR文件:
EAR文件内的所有资源适配器作为基本连接器部署。假如存在多个资源适配器,则它们的部署次序就是它们在application.xml部署描述器中列出的次序。
部署所有EJB模块。由于EJB可能在初始化期间用到某些资源适配器,所以EJB的部署在资源适配器之后。假如存在多个EJB模块,它们的部署次序将是它们在application.xml中列出的次序。
部署所有Web应用模块。由于Web应用初始化期间可能用到资源适配器和EJB,所有Web应用在这两者之后部署。假如存在多个Web应用模块,它们部署次序就是它们在application.xml中列出的次序。
二、依靠库的问题
在J2EE应用封装和部署过程中,最常见的问题出现在工具类和支持类上。封装Web应用或EJB应用时,这些库应该放在哪里?Web应用和EJB应用一 般都有被“卸出”(这里指装入的反向过程)的能力,这种能力由部署时装入它们的类装载器支持。假如我们把工具类和支持类放入应用服务器的标准类路径,这些 类很可能完全失去被卸出的能力。这样,假如Web应用或EJB应用要更新某个库的版本,重新部署Web应用或EJB应用时,包含工具类和支持类的依靠库也 要重新部署。在这种情形下,把工具类放入应用服务器标准类路径很不方便,因为每次部署Web应用和EJB应用时,都要重新启动整个应用服务器,这显然不是 理想的选择。
那么,在J2EE标准定义中,假定依靠库放在哪里才能实现运行时的重新部署(热部署)呢?有两个简单的方案,但从根本上来说两者都不甚合理:
以JAR文件形式封装的依靠库可以放入Web应用的WEB-INF\lib目录。一般地,WEB-INF\lib目录基本上只用来存放Servlet,jsp页 面和Servlet会在读取新类时寻找该目录。假如工具类库只供一个Web应用的JSP页面和Servlet使用,应该说这个方案已经足够。然而,假如 EJB组件、JMS消费者、启动应用的类和关闭应用的类也要用到同一工具类库,这种方案不再有效,因为对于它们来说,WEB-INF\lib目录是不可见 的。
除了把工具类库放入WEB-INF\lib目录之外,同时在每一个EJB JAR文件中包含一份完整的拷贝。部署EJB时,EJB类装载器将只在它自己的JAR文件中寻找被引用的工具类,不去查看其他已部署EJB应用的JAR文 件和WEB-INF\lib目录。假如有几个EJB应用都要用到同一个工具类库,则在每一个JAR文件中放入该类库的一份拷贝就能解决问题。虽然这种方案 实现了依靠库的热部署能力,但它明显地不够完善。封装JAR文件的目的是为了提高应用的模块化程度,把同一个类文件放入多个JAR包正好是背其道而行之。 此外,多次复制同一组类无谓地加大了应用的体积。最后,即使只改变一个库,每一个JAR文件也都要重新构造,从而使构造过程复杂化。
下面我们来看两种较为有效的解决方案。
2.1 解决方案之一
要解决这个问题,一种可能的方案是在J2EE中避免使用多个JAR文件,把所有EJB和工具类聚集成单个包。EJB 2.0规范正在推动几个项目进行这方面的工作。这个规范要求参与关系的实体EJB使用本地引用,因此参与关系的各个EJB必须封装到同一个JAR文件。
由于新的规范要求避免使用远程关系,因此,许多供给商正在考虑提供能够把多个EJB JAR文件合并的工具。这些工具能够读取两个合法的EJB JAR文件,把它们的类和部署描述器合并成单个统一的包。但应当注重的是,即使所有EJB组件都聚合到了单个JAR文件里面,避免了在多个EJB之间复制 依靠库,但假如Web应用也要用到依靠库,则WEB-INF\lib目录下仍然需要依靠库的副本。
此外,对EJB应用模块化的需求仍然存在,许多人希望能够单个地部署EJB。因为重新部署一个JAR文件时,该JAR文件内的每一个EJB都将重新部署,假如实际要部署的只是单个EJB,部署过程中就会出现许多不必要的操作。
2.2 解决方案之二
随着JDK 1.3的发布,Sun重新定义了支持可选包必不可少的“扩展机制”。这个扩展机制支持两方面功能:
JAR文件可以声明自己对其他JAR文件的依靠性。
类装载器经过了修改,能够在可选的包和应用路径中搜索类。
J2EE 1.3规范要求应用服务器必须提供这方面的支持。这就要求部署描述工具能够装载所有通过扩展机制定义的可选库。它同时也意味着,假如一个应用服务器或部署 工具能够在运行时卸出或重新部署那些通过扩展机制使用库的EJB应用,那么,该应用服务器或工具也支持所有依靠库的卸出或重新部署。
这种扩 展机制为Web应用WAR文件和EJB应用JAR文件指定自己需要哪些企业应用EAR文件中的依靠库提供了一种标准化的方法。那么,这种扩展机制是如何工 作的呢?每一个JAR文件里都有一个manifest(意为载货单、旅客名单)文件,这个文件由jar工具自动创建,默认名字是manifest.mf。 JAR文件可以在manifest文件中加入一个Class-Path属性,引用它所依靠的JAR文件。我们可以手工编辑manifest.mf文件,在 原有内容的基础上,添加Class-Path属性。实际上,许多供给商提供的EJB封装工具会在封装过程中处理依靠类,自动创建合适的 manifest.mf文件,使这个文件包含正确的Class-Path属性。
假如在创建EJB JAR文件时修改了manifest.mf,引入了Class-Path属性,在生成一个新的EJB应用文件时,应用服务器提供的容器生成工具必须保存这 个值。在WebLogic Server 6.1下,假如EJB JAR已经在manifest.mf文件中包含Class-Path属性,weblogic.ejbc工具会在生成新EJB应用时保存这个值。当前,专门 用来创建Class-Path属性并把它插入manifest.mf的工具还没有出现,所以这个工作有时还需要通过手工编辑JAR文件的manifest 文件进行。
Class-Path属性的值是用来搜索工具类库的相对URL。这个URL总是相对于包含Class-Path属性的组件(而不 是EAR文件的根)。单个Class-Path属性内可以指定多个URL,一个manifest文件可以包含多个Class-Path属性。Class- Path属性的一般格式是:
Class-Path: 列出用空格分隔的多个JAR文件名字
下面是一个例子:
Class-Path: mylog4j.jar xmlnew.jar foo/bar/myutil.jar
在J2SE应用中使用这种扩展机制时,Class-Path属性可以引用目录。然而,对于全部内容都包含在JAR文件中的J2EE应用,Class- Path属性只能引用其他JAR文件。此外,在manifest文件中,Class-Path属性声明必须在一个独立的行上,以便与其他属性声明区分。
这种扩展机制的功能非常强大。非凡地,通过创建一个以解析次序为最终次序的、包含所有类的统一类路径,它能够方便地解决循环引用问题。例如,在下面这个例子中,假设首先被解析的是MyEJB1.jar。MyEJB1.jar引用了:
Class-Path: jaXP1.jar MyEJB2.jar ..\xmlnew.jar
此时,类装载器将解析MyEJB2.jar。MyEJB2.jar引用了:
Class-Path: jaxp1.jar MyEJB1.jar
类装载器最终使用的“应用级类路径”将是:
Class-Path: jaxp1.jar MyEJB2.jar ..\xmlnew.jar MyEJB1.jar
2.3 依靠库应用实例
下面这个例子示范了一个企业应用各种可能的类装载情形。它示范了多个EJB模块、多个Web应用,以及在这些应用之间多个共享的依靠库。通过这个例子, 我们可以了解应用服务器从不同应用装载各个类的过程。当应用运行时,通过输出不同类的类装载器层次关系,我们可以了解:是否所有的类都通过单个类装载器装 入,还是通过不同的类装载器装入;假如通过多个类装载器装入,这些装载器有什么关系。
这个例子包含两个EJB模块、两个Web应用模块、七个在不同情形下使用的依靠类库。EAR文件的结构如下:
MyDepend1-container.jar
MyDepend2-container.jar
MyWebApp1.war
MyWebApp2.war
TestUtil1.jar
TestUtil2.jar
TestUtil3.jar
TestUtil4.jar
TestUtil5.jar
TestUtil6.jar
TestUtil7.jar
META-INF\
application.xml
每一个“MyDepend?-container”JAR文件包含一个EJB。每一个Web应用中包含一个名为TestServlet的 Servlet。每一个工具类库包含一个类,这个类有一个方法,它的功能是输出类装载器的层次关系。这个例子测试了EAR文件内许多不同的类装载情形,其 中包括:
当一个EJB用到一个依靠库,且在EJB manifest里面的类路径中引用它时,它是如何装载的?
当不同EJB模块内的多个EJB共享一个依靠库,且依靠库通过各个EJB的manifest类路径指定时,它是如何装载的?
当Web应用引用一个依靠库,且通过Web应用模块的manifest路径引用依靠库时,它是如何装载的?
当Web应用引用一个依靠库,且依靠库保存在Web应用模块的WEB-INF\lib目录下时,它是如何装载的?
当一个EJB模块和一个Web应用都在它们的manifest路径中引用一个依靠库时,依靠库是如何装载的?
要执行这个例子,请先把MyDepend.ear文件(从本文后面下载源文件)部署到服务器上,然后运行各个Web应用的TestServlet。 TestServlet将调用适当的EJB方法,EJB的方法又调用依靠库中类的方法。下面是执行两个Servlet的URL:
http://<服务器名字>:<端口>/web1/testservlet/
http://<服务器名字>:<端口>/web2/testservlet/
WebLogic Server 6.1控制台输出如下:
下面是application.xml部署描述器:
Inc.//DTD J2EE Application 1.2//EN' 'http://java.sun.com/j2ee/dtds/application_1_2.dtd'>
App Name
MyDepend1-container.jar
MyDepend2-container.jar
MyWebApp1.war
web
MyWebApp2.war
web2
第一个EJB模块的manifest声明的Class-Path属性是:
Class-Path: TestUtil 1.jar TestUtil3.jar TestUtil 6.jar TestUtil7.jar
其他EJB模块和Web应用模块的manifest类路径声明都有所不同,它们是EAR文件包含的七个依赖库的不同组合。Web应用中包含的各个Servlet提供有关执行过程的详细信息,具体请参见各个组件的源代码。
毫无疑问,manifest.mf文件里面声明的类路径有助于提高J2EE应用的模块化。使用这种技术时,我们可以通过一种简单的模式确定哪些EJB应该封装为一个JAR文件,哪些应该封装为另一个JAR文件:
标识出一个参与CMR(Container-Managed Relationship)关系的实体EJB。标识出所有可以从这个源实体EJB通过CMR关系到达的实体EJB。把这个关系图中的EJB封装为一个EJB JAR。为每一组独立的实体EJB关关系到达的实体EJB。把这个关系重复这个过程。
分析业务和技术方面的需求,如果有必要的话,把多个JAR文件合并成一个。如果修改单个EJB时重新部署多个EJB是可接受的,则可以用单个JAR文件封装多个EJB。
每一个EJB JAR文件必须通过manifest的Class-Path列出其依赖关系。类装载器将自动地解决循环引用和重复引用问题。例如,在前面演示依赖关系的例子中,多个EJB引用了第三个解决循环引用和重复引用问题。例如,在前面演示依赖关系的例子中,多个EJB引用了第三个库。但是,虽然存在这种重复引用,EAR类装载器只装载该库一次。
来源:
http://java.chinaitlab.com/core/2019.html
http://blog.163.com/long_cai_edu/blog/static/45242658200841192132178/
http://www.knowsky.com/366355.html