JBoss AS 7类加载说明

这是示例章节,摘自Francesco Marchioni编辑的JBoss AS 7 Configuration Deployment and Administration一书,该书正在运行一个名为mastertheboss.com的JBoss门户。

根据Java EE规范的要求,理想情况下,应用程序服务器应为其部署的应用程序提供使用任何实用程序库和任何版本的自由,而不必考虑要使用同一库的并发应用程序的存在。

这也称为名称空间隔离(Java EE 5规范,EE.8.4节)。 但是,从不同名称空间加载类可能会引起一些不易解决的问题:例如,如果我在应用程序中打包了新版本的实用程序库,而应用程序加载了同一个库的旧版本,将会发生什么情况?服务器? 或者,如何在应用程序服务器的同一实例中同时使用同一实用程序库的两个不同版本? 多年来,JBoss AS类加载策略已经发生了明智的变化:基本上,应用服务器的4.x版本使用UnifiedClassLoader ,其目的是减少运行的应用程序之间的通信开销,因为类数据可以通过引用或简单副本共享。

使用UnifiedClassLoader无法解决的主要未解决问题之一是类加载依赖项。 这样的想法是,如果一个应用程序(A)使用另一个应用程序(B)的类,则系统应该知道在重新部署B时重新部署A,否则它将引用陈旧的类。 实际上,有两种尝试来使这项工作有效,而无需用户进行任何配置。 两种尝试均未真正奏效,并且均被放弃。 自从JBoss AS 5.0引入以来,基于新的虚拟文件系统(VFS)的新类加载器。 实施VFS是为了简化和统一应用程序服务器中的文件处理。 新的类加载器名为VFS类加载器,它使用VFS查找JAR和类文件。 即使这表示在JBoss AS 5.0中如何加载类,也发生了重大变化,但是所产生的行为与JBoss AS以前的版本非常相似。

错误的常见来源是在部署中包括由容器提供的API类。 这会导致创建该类的多个版本,并且部署无法正确部署。 AS7中的类加载标志着与以前的尝试大相​​径庭。 现在,类加载基于JBoss模块项目,并且所部署的任何应用程序实际上都是模块。 肯定的读者会提出一些疑问:分配给已部署应用程序的模块名称是什么? 而且,AS如何处理模块之间的依赖关系? 让我们在单独的部分中回答每个问题:

了解模块名称

了解模块名称不是学术活动。 实际上,我们可以在模块之间建立依赖关系,因此在许多情况下,需要知道分配给应用程序的模块名称是哪一个。 因此,打包为顶级归档文件(例如WAR,JAR和SAR)的应用程序将获得以下模块名称:

deployment.[archive name]

例如,将部署一个名为WebExample1.war的Web应用程序作为模块名称:

deployment.WebExample1.war

另一方面,在包含嵌套模块的应用程序(例如EAR归档文件)上,将使用以下分类为每个单个归档文件分配模块名称:

deployment.[ear archive name].[sub deployment archive name]

因此,如果将相同的Web应用程序包含在存档EnterpriseApp.ear中 ,则将使用以下名称进行部署:

deployment.EnterpriseApp.ear.WebExample1.war

查找隔离级别

第2章“配置应用程序服务”中 ,我们有意部署了使用log4j Api的应用程序,并将log4j库添加到WEB-INF / lib文件夹中。 该应用程序的部署很顺利,省去了一个问题:为什么我们需要添加已经作为模块包含在应用程序服务器中的库? (在我们的例子中,在modules \ org \ apache \ log4j \ main路径中)。

一般规则是,在JBoss AS 7上,每个已部署的应用程序模块都与其他模块隔离开来。 这意味着,默认情况下,它在AS模块上不可见,在AS模块上也不对应用程序可见。

但是,使用应用程序服务器模块非常容易,并且可以用一句话来概括:将依赖项添加到所需模块中,AS就会使用它。 应用程序服务器会自动添加依赖项,或者它们需要由用户发出信号:

  • 核心模块库(即企业类)被视为隐式依赖项,因此当部署者检测到它们的使用时,它们会自动添加到您的应用程序中
  • 用户需要在应用程序的MANIFEST文件或定制的JBoss部署文件jboss-deployment-structure.xm l中明确声明其他模块库(有关更多信息,请参见“高级部署策略”部分)。

隐式依赖:

指出企业应用程序通常使用的Api依赖项可能很麻烦。 因此,正如我们预期的那样,应用程序服务器会自动为您添加它们。 当应用服务器检测到某些该模块的典型注释或配置文件时,将添加一些注释或配置文件。 例如,添加beans.xml文件会触发自动焊接依赖。

以下思维导图显示了隐式添加到应用程序中的模块的综合视图:

该图像的含义很简单:如果您的应用程序使用了所示的任何核心模块,那么您无需指定任何依赖项,因为应用程序服务器能够自动链接该模块。 显式依赖项不能被定义为隐式依赖项的模块需要由用户声明。 在最初的示例中,未将log4j库作为隐式依赖项提及,因此我们不得不将log4j JAR与应用程序打包在一起。 但是,我们可以指示部署者使用log4j库,该库捆绑在应用程序服务器分发中。 实现它的最简单且推荐的方法是在META-INF / MANIFEST.MF中包括Dependencies:[module]声明。 在我们的情况下,要使您的应用程序依赖于log4j,只需在清单文件中包含以下代码:

依赖项:org.apache.log4j

请注意,模块名称并不总是与库的软件包名称匹配。 实际的模块名称由module元素的name属性在module.xml文件中指定。

用户通常将使用Eclipse(或任何其他IDE)来更新清单文件,而无需执行任何繁琐的存档更新:

您不仅限于单个依赖项,还可以添加多个以逗号分隔的依赖项。 例如,为了同时添加对log4j和Apache Velocity Api的依赖,可以使用以下命令:

依赖项:org.apache.log4j,org.apache.velocity

您甚至可以通过添加export关键字将一个应用程序模块使用的依赖项导出到其他应用程序。 例如,在较早的应用程序中,我们现在将依赖项导出到其他模块:

标为依赖于Deployment.WebApp.war模块的应用程序还将有权访问其依赖项:

export参数还可以用于将依赖项导出到耳朵中包含的所有子部署。 因此,如果从耳朵的顶层(或通过ear / lib目录中的jar)导出依赖关系,则该依赖关系也将对所有子部署单元可用。

在META-INF / MANIFEST.MF中,您还可以指定其他命令,这些命令可以修改服务器部署程序的行为。 例如,可以添加可选属性,以指定如果在部署时未找到模块,则部署不会失败。

最后,当指定了services关键字时,部署者将尝试加载放置在归档文件的META-INF / services中的服务。

服务Api已在Java SE 6中公开。服务可以定义为一组编程接口和类,它们提供对某些特定应用程序功能或特性的访问。 服务提供者接口(SPI)是服务定义的一组公共接口和抽象类。

您可以通过实现服务提供商API来定义服务提供商。 通常,您将创建一个JAR文件来保存您的提供程序。 要注册您的提供程序,您必须在JAR文件的META-INF / services目录中创建一个提供程序配置文件。 将services属性添加到META-INF / MANIFEST.MF时,您实际上将能够加载META-INF / services目录中包含的服务。

有关SPI Api的出色介绍,请访问:http://java.sun.com/developer/technicalArticles/javase/extensible。

设置全局模块

该选项与用于加载公共库的旧AS方法有点类似,您曾经将它们放置在文件夹JBOSS_HOME / common / lib中。 如果在standalone.xml / domain.xml中定义了名为global-modules的部分,则将使该模块可被其他AS模块访问。 例如,您可以选择使用以下部分来代替声明对log4j的依赖关系:

<subsystem xmlns="urn:jboss:domain:ee:1.0">
  <global-modules>
    <module name="org.apache.log4j" />
  </global-modules>
</subsystem>

尽管通常不建议使用这种方法,但是由于它使我们回到了单片应用服务器的概念,因此它仍然可以带来一些好处。 例如,如果您要迁移一些较旧的应用程序,并且您不希望或者根本无法将依赖关系指定到存档中。

进阶部署策略

到目前为止,我们所学的知识足以配置许多类型的应用程序。 如果您使用的是复杂的归档配置,例如具有多个模块和依赖项的EAR归档,那么在单个文件中定义类加载策略将很有用。

配置文件jboss-deployment-structure.xml可以做到这一点。 使用此文件的优点有很多:

  • 您可以在一个文件中定义所有应用程序模块的依赖关系
  • 您可以通过包含/排除所有或部分模块来使用更细粒度的方式加载模块类
  • 您可以为打包在企业归档中的应用程序定义类加载隔离策略

让我们看一些实际的例子,jboss-deployment-structure.xml可以为您做什么。

设置单个模块依赖性

我们已经学习了如何使用归档文件的MANIFEST文件中的Dependencies属性来激活log4j依赖关系。 使用jboss-deployment-structure.xml文件可以达到相同的效果。 让我们回顾一下存档结构,它基本上是由一个名为WebApp.war的Web应用程序组成的。

如您所见,文件jboss-deployment-structure.xml需要放置在EAR的META-INF文件夹中。

其内容如下:

<jboss-deployment-structure>
  <sub-deployment name="WebApp.war">
    <dependencies>
      <module name="org.apache.log4j" />
    </dependencies>
  </sub-deployment>
</jboss-deployment-structure>

文件jboss-deployment-structure并非专用于EAR。 实际上,您也可以将其放置在WebApp应用程序中,方法是将其放置在存档的WEB-INF文件夹中。 但是,它仅适用于顶级归档。 因此,如果将jboss-deployment-structure.xml放在WAR的WEB-INF文件夹中,并且将WAR打包在EAR归档中,则将忽略jboss-deployment-structure.xml。

该文件的相关部分是sub-deployment元素,该元素引用Web应用程序(包括其中的依赖项)。 预期的结果是应用程序服务器将触发对log4j Api的依赖关系,因此我们的Web应用程序将看到该依赖关系。

排除服务器自动依赖项

在本章的前面,我们已经展示了当满足某些条件时,应用程序服务器如何能够自动触发某些依赖关系。 例如,如果部署JSF应用程序(包含faces-config.xml文件),那么将自动添加JSF 2.1 Api实现。

例如,这可能并不总是所需的选项,因为您要为该模块提供另一个发行版实现。 您可以使用jboss-deployment-structure.xml中的排除部分轻松实现此目标,如下所示:

<jboss-deployment-structure>
  <deployment>
    <exclusions>
      <module name="javax.faces.api" />
      <module name="com.sun.jsf-impl" />
    </exclusions> 
    <dependencies>
      <module name="javax.faces.api" slot="1.2"/> 
      <module name="com.sun.jsf-impl" slot="1.2"/>
    </dependencies> 
  </deployment>
</jboss-deployment-structure>

注意,在“依赖项”部分中,我们添加了备用JSF 1.2实现,您的应用程序将使用该实现。 实际上,此JSF实现随slot属性指定的文件夹下的应用程序服务器分发以及javax.faces.api模块路径一起提供。 在我们的例子中,这对应于JBOSS_HOME / modules / javax / faces / api / 1.2文件夹。

隔离子部署

假设您有一个由Web应用程序,EJB模块和包含实用程序类的JAR文件组成的应用程序。 所有子部署均位于存档的根目录,因此它们将能够彼此看到。 但是,假设您的Web应用程序自身包含相同EJB的某些实现,这可能会很方便。 这是绝对可能的,因为Java EE 6规范允许您的Web应用程序在WEB-INF / classes或WEB-INF / lib文件夹中包括EJB类。

类加载器如何解决此冲突? 加载用于避免已加载类之间的任何冲突的类时,应用程序服务器类加载器具有优先级列表。

  • 容器(包括Java EE API)自动将模块的最大优先级赋予模块。 包含在modules文件夹中的库在此类别中。
  • 然后,用户在打包档案的MANIFEST.MF中将其指示为Dependencies(或在jboss-deployment-structure.xml文件中)。
  • 接下来,打包在应用程序内部的库,例如WEB-INF / lib或WEB-INF / classs中包含的类。
  • 最后,打包在同一EAR归档文件中的库(在EAR的lib文件夹中)。

因此,在此示例中,位于WEB-INF文件夹中的EJB库将“隐藏” EJB.jar顶级部署的实现。 无论这是否是容器中所需的操作,您仍然可以覆盖它:

<jboss-deployment-structure> 
  <ear-subdeployments-isolated>false</ear-subdeployments-isolated> 
  <sub-deployment name="WebApp.war">
    <dependencies>
      <module name="deployment.App.ear.EJB.jar" />   
    </dependencies>
  </sub-deployment>
</jboss-deployment-structure>

在此示例中,我们向EJB.jar添加了一个依赖关系,该依赖关系位于存档的根目录,它将覆盖Web应用程序中打包的实现。

请注意, ear-subdeployments-isolated元素位于文件顶部。 通过设置EAR隔离级别,您将能够指示子部署模块是否彼此可见。

此属性的默认值为false ,这意味着子部署模块将能够看到彼此。 如果将隔离设置为true,则每个模块将由不同的类加载器接收,因此,在我们的示例中,Web应用程序将无法找到EJB.jarUtility.jar库中包含的类。

如果要使部署保持隔离状态,但允许其中一些可见,则可以选择以下几种方法:

  • 将库移至EAR / lib文件夹,以便将其作为单独的模块使用
  • 使用依赖关系或调用应用程序的MANIFEST.MF文件中的类路径指定依赖关系

从以下屏幕截图中,您可以看到如何通过将公共库放置在lib文件夹中并向EJB类添加依赖项来正确设置EAR:

这是jboss-deployment-structure.xm l中所需的相应配置:

<jboss-deployment-structure> 
  <ear-subdeployments-isolated>true</ear-subdeployments-isolated>      
  <sub-deployment name="WebApp.war">
    <dependencies>
      <module name="deployment.App.ear.EJB.jar" /> 
    </dependencies>
  </sub-deployment>
</jboss-deployment-structure>

可以使用共享库中的打包库,因为Java EE 5通常用于保存EAR的所有模块所使用的JAR文件。

共享库的默认名称是lib,但是您可以随时使用META-INF / application.xml文件中的library-directory元素覆盖它。 例如,假设您要使用公用文件夹来保存共享库,则可以将其添加到application.xml中

<library-directory>common</library-directory>

作为附带说明,我们建议您避免在共享文件夹中放置声明组件的注释(例如EJB3),因为它可能对部署过程产生意想不到的不良后果。 因此,我们强烈建议您仅将实用程序类放在共享库文件夹中。

使用类路径声明解决依赖关系:

到目前为止,我们已经使用JBoss的方法解决了模块之间的依赖关系,我们显然建议将其作为首选。 尽管如此,我们也应该考虑Java引用EAR文件中包含的一个或多个库的可移植方式。

可以使用模块的MANIFEST.MF文件中的Class-Path属性来完成此操作,该属性需要引用另一个应用程序无法看到的库(请看前面的示例,带有隔离集的部署单元)为true )。

例如,假设您需要从Web应用程序中引用Utility.jar应用程序,然后只需将以下内容添加到META-INF / MANIFEST.MF中:

  • 清单版本:1.0
  • 类路径:Utility.jar

实际上,您可以在Class-Path中包含多个库,并以逗号分隔它们,这与使用JBoss的Dependencies属性的方式非常相似。 与Dependencies属性不同,Class-Path属性指向引用依赖库的实际JAR文件名(而不是模块名)。

在类路径方法和JBoss的Dependencies方法之间进行选择,取决于应用程序的结构:通过使用JBoss的Dependencies,您可以购买到更多的选项,尤其是将Dependencies导出到其他部署的能力。较早。 支持JBoss的Dependencies方法的另一点是引用模块的能力,这些模块实际上并未打包在应用程序中。 例如,我们已经了解了如何向服务器分发的一部分log4j Api添加依赖项。

另一方面,类路径方法的主要优点取决于应用程序的可移植性。 因此,如果您将全便携式解决方案作为优先事项,则可以考虑切换到Class-Path清单属性。

这是示例章节,摘自Francesco Marchioni编辑的JBoss AS 7 Configuration Deployment and Administration一书,该书正在运行一个名为mastertheboss.com的JBoss门户。


翻译自: https://www.javacodegeeks.com/2012/09/jboss-as-7-classloading-explained.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值