第 3 章 移植您的应用程序
3.1. 多数应用程序要求的修改
3.1.1. 复查多数程序所要求的修改
3.1.2. 类加载的修改
3.1.2.1. 根据类加载的变化更新应用程序
- 首先,查看您的应用程序的软件包结构及其依赖关系。详情请参考 第 3.1.2.3 节 “根据类加载的修改更新应用程序的依赖关系”。
- 如果您的应用程序使用了日志,您需要制定正确的模块依赖关系。请查看 第 3.1.4.1 节 “修改日志依赖关系” 里的相关细节。
- 由于模块化类加载的修改,您可能需要修改 EAR 或 WAR 的软件包结构。详情请参考 第 3.1.5.1 节 “修改 EAR 和 WAR 的打包”。
3.1.2.2. 了解模块依赖关系
模块只能访问自己的类,以及它具有显性或隐性依赖关系的任何模块上的类。
过程 3.1. 了解模块依赖关系
了解隐性依赖关系
服务器里的部署者隐性地自动添加一些常用的模块依赖关系,如javax.api
和sun.jdk
。这使得类在运行时对于部署可见,并让开发人员不用显性地添加依赖关系。关于如何和何时添加这些隐性的依赖关系,请查看 https://access.redhat.com/site/documentation/JBoss_Enterprise_Application_Platform/ 上的《JBoss EAP 6 开发指南》里的『类记载和模块』章节的『隐性模块依赖关系』。了解显性依赖关系
对于其他类,模块必须显性地指定,否则缺失的依赖关系会导致部署或运行时错误。如果缺失了依赖关系,您可以在服务器日志里看到ClassNotFoundExceptions
或NoClassDefFoundErrors
跟踪信息。如果多于一个模块加载了相同的 JAR 或一个模块加载的类扩展了不同模块加载的类,您会在服务器日志里看到ClassCastExceptions
。要显性地制定依赖关系,请修改MANIFEST.MF
或创建一个 JBoss 专有的部署描述符文件jboss-deployment-structure.xml
。关于模块依赖关系的更多信息,请查看 https://access.redhat.com/site/documentation/JBoss_Enterprise_Application_Platform/《JBoss EAP 6 开发指南》里的『开发应用程序起步』章节的『类记载和模块概述』。
3.1.2.3. 根据类加载的修改更新应用程序的依赖关系
JBoss EAP 6 里的类加载和以前版本的很不一样。类加载现在基于 JBoss Modules 项目。它不是一个加载所有 JAR 到普通 Class path 里的单一的、层级的类加载器,而是每个库都成为一个模块,链接它所依赖的模块。JBoss EAP 6 里的部署也是模块,它们不能访问应用服务器里 JAR 中定义的类,除非在这些类上显性地定义了依赖关系。应用服务器里定义的一些模块依赖关系是自动设置的。例如,如果您在部署一个 Java EE 应用程序,Java EE API 的依赖关系将被自动或隐性地添加到您的模块里。关于自动添加的依赖关系的完整列表,请参考 https://access.redhat.com/site/documentation/JBoss_Enterprise_Application_Platform/ 上的《JBoss EAP 6 开发指南》的『类加载和模块』章节里的『隐性模块依赖关系』。
当您移植程序到 JBoss EAP 6 时,由于模块化类加载的变化,您可能需要执行一个或多个下列任务:
3.1.3. 配置文件的修改
3.1.3.1. 创建或修改控制 JBoss EAP 6.0 里类加载的文件
由于 JBoss EAP 6 里对于使用模块化类加载的修改,您可能需要修改或创建一个或多个文件来添加依赖关系或阻止对自动依赖关系的加载。关于类加载和类加载次序的更多信息,请参考 https://access.redhat.com/site/documentation/JBoss_Enterprise_Application_Platform/ 上的《JBoss EAP 6 开发指南》里的『类加载与模块』章节。
- jboss-web.xml
- 如果您已经在
jboss-web.xml
文件里定义了一个<class-loading>
元素,您需要删除它。JBoss EAP 5 里使用的这个行为现在是 EAP 6 里的默认类加载行为,所以不是必需的了。如果您没有删除这个元素,您会在服务器日志里看到一个 ParseError 和 XMLStreamException。下面是jboss-web.xml
文件里已注释的<class-loading>
元素的例子。<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 4.2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_2.dtd"> <jboss-web> <!-- <class-loading java2ClassLoadingCompliance="false"> <loader-repository> seam.jboss.org:loader=MyApplication <loader-repository-config>java2ParentDelegation=false</loader-repository-config> </loader-repository> </class-loading> --> </jboss-web>
- MANIFEST.MF
- 手动编辑的
- 根据您的应用程序使用的组件或模块,您可能需要添加一个或多个以来关系到这个文件里。您可以添加它们为
Dependencies
或Class-Path
条目。下面是开发人员编辑的MANIFEST.MF
例子:Manifest-Version: 1.0 Dependencies: org.jboss.logmanager Class-Path: OrderManagerEJB.jar
如果您修改了这个文件,请确保在文件结尾包含一个新行符号。 - 用 Maven 生成的
- 如果您使用 Maven,您需要修改您的
pom.xml
文件以生成用于MANIFEST.MF
的依赖关系。如果您的应用程序使用了 EJB 3.0,您可能在pom.xml
文件里有如下内容:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <configuration> <ejbVersion>3.0</ejbVersion> </configuration> </plugin>
如果 EJB 3.0 代码使用了org.apache.commons.log
,您需要在MANIFEST.MF
文件里有这个以来关系。要生成这个以来关系,请添加<plugin>
元素到pom.xml
文件里:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ejb-plugin</artifactId> <configuration> <ejbVersion>3.0</ejbVersion> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin>
在上面的例子里,src/main/resources/META-INF/MANIFEST.MF
文件只需要包含以来关系条目:Dependencies: org.apache.commons.logging
Maven 将生成完整的MANIFEST.MF
文件:Manifest-Version: 1.0 Dependencies: org.apache.commons.logging
- jboss-deployment-structure.xml
- 这个文件是 JBoss 专有的部署描述符,它可以用来对类加载的细颗粒度控制。就像
MANIFEST.MF
一样,这个文件可以用来添加依赖关系。它也可以阻止添加自动依赖关系、定义额外的模块、修改 EAR 部署的隔离类加载行为,以及在模块里添加其他的资源根目录。下面是一个jboss-deployment-structure.xml
文件,它添加 JSF 1.2 模块的依赖关系且阻止了 JSF 2.0 模块的自动加载。<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0"> <deployment> <dependencies> <module name="javax.faces.api" slot="1.2" export="true"/> <module name="com.sun.jsf-impl" slot="1.2" export="true"/> </dependencies> </deployment> <sub-deployment name="jboss-seam-booking.war"> <exclusions> <module name="javax.faces.api" slot="main"/> <module name="com.sun.jsf-impl" slot="main"/> </exclusions> <dependencies> <module name="javax.faces.api" slot="1.2"/> <module name="com.sun.jsf-impl" slot="1.2"/> </dependencies> </sub-deployment> </jboss-deployment-structure>
关于这个文件的其他信息,请参考 第 3.1.3.2 节 “jboss-deployment-structure.xml”。 - application.xml
- 在以前的 JBoss EAP 版本里,您通过
jboss-app.xml
控制 EAR 里部署的顺序。现在不是这样了。Java EE6 规格在application.xml
文件里提供了<initialize-in-order>
元素来控制 EAR 里的 Java EE 模块的部署顺序。在大多数情况下,您不许要指定部署顺序。如果您的应用程序使用了依赖关系注入和 resource-refs 来引入外部模块的组件,多数情况下都不要求<initialize-in-order>
元素,因为应用服务器能够隐性地确定正确和优化的组件顺序。让我们假设您有一个包含myBeans.jar
且myApp.war
打包在myApp.ear
里的应用程序。myApp.war
使用@EJB
注解从myBeans.jar
注入一个 bean。在这个例子里,应用服务器懂得如何确保 EJB 组件在 servlet 启动之前可用,而您不需要使用<initialize-in-order>
元素。然而,如果这个 servlet 使用了如下的传统 JNDI 查找风格的远程引用来访问 bean,您可能需要指定模块的顺序。init() { Context ctx = new InitialContext(); ctx.lookup("TheBeanInMyBeansModule"); }
在这种情况下,服务器不能确定 EJB 组件处于myBeans.jar
里,您需要强制myBeans.jar
里的组件被初始化并在myApp.war
里的组件之前启动。为此,您可以设置<initialize-in-order>
元素为true
并指定application.xml
文件里的myBeans.jar
和myApp.war
的顺序。下面是一个使用<initialize-in-order>
元素来控制部署顺序的例子。myBeans.jar
在myApp.war
文件之前被部署。<application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="6" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd"> <application-name>myApp</application-name> <initialize-in-order>true</initialize-in-order> <module> <ejb>myBeans.jar</ejb> </module> <module> <web> <web-uri>myApp.war</web-uri> <context-root>myApp</context-root> </web> </module> </application>
application.xml
文件的 schema 可以在这里找到:http://java.sun.com/xml/ns/javaee/application_6.xsd。注意
您应该意识到设置<initialize-in-order>
元素为true
会减慢部署速度。我们更倾向于使用依赖注入或 resource-refs 来定义正确的依赖关系,因为它们使容器在优化部署时更具灵活性。 - jboss-ejb3.xml
jboss-ejb3.xml
部署描述符替换jboss.xml
以覆盖和添加 Java EE 定义的ejb-jar.xml
里提供的功能。这个新文件和jboss.xml
兼容,而目前的部署里已经忽略了jboss.xml
。- login-config.xml
login-config.xml
文件不再用于安全配置。现在安全性是在服务器配置文件的<security-domain>
元素里配置。这个文件是standalone/configuration/standalone.xml
,如果您是在受管域里运行服务器, 则是domain/configuration/domain.xml
。
3.1.3.2. jboss-deployment-structure.xml
jboss-deployment-structure.xml
是 JBoss EAP 6 的一个新的可选的部署描述符。这个部署描述符提供了对部署里的类加载的控制。
EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd
。
3.1.3.3. 新模块化类加载系统的软件包资源
在以前的 JBoss EAP 版本里,WEB-INF/
里面的所有资源都添加到了 WAR classpath。在 JBoss EAP 6 里,web 应用程序的 artifact 只从 WEB-INF/classes
和 WEB-INF/lib
目录进行加载。没有在指定位置打包应用程序 artifact 会导致 ClassNotFoundException
, NoClassDefError
或运行时错误。
- 修改资源打包
- 要使资源只对应用程序可用,您必须将属性文件、JAR 或其他具有 WAR 的 artifact 移至
WEB-INF/classes/
或WEB-INF/lib/
目录来进行绑定。详情请参考 第 3.1.3.4 节 “修改 ResourceBundle 属性的位置”。 - 创建自定义模块
- 如果您想使自定义的资源对于运行在 JBoss EAP 服务器上的所有应用程序可用,您必须创建一个自定义的模块。关于这个途径的详情,请参考 第 3.1.3.5 节 “创建自定义模块”。
3.1.3.4. 修改 ResourceBundle 属性的位置
在以前的 JBoss EAP 版本里,EAP_HOME/server/SERVER_NAME/conf/
目录位于 classpath 里且可为应用程序所用。要使属性为 JBoss EAP 6 里的应用程序的 classpath 所用,您必须将其打包至您的应用程序里。
过程 3.2. 修改 ResourceBundle 属性的位置
- 如果您在开发 WAR 归档,您必须将这些属性包裹至 WAR 的
WEB-INF/classes/
目录里。 - 如果您想要 EAP 里所有组件都可以访问这些属性,那您必须将其打包到 JAR 的根目录并将 JAR 放入 EAR 的
lib/
目录下。
3.1.3.5. 创建自定义模块
过程 3.3. 创建自定义模块
- 创建和填充
module/
目录结构。- 在
EAP_HOME/module
目录下创建一个目录结构来包含文件和 JAR。例如:$ cd EAP_HOME/modules/
$ mkdir -p myorg-conf/main/properties
- 将属性文件移到您在前一步骤里创建的
EAP_HOME/modules/myorg-conf/main/properties/
目录里。 - 在
EAP_HOME/modules/myorg-conf/main/
目录里创建一个包含下列 XML 内容的module.xml
文件:<module xmlns="urn:jboss:module:1.1" name="myorg-conf"> <resources> <resource-root path="properties"/> </resources> </module>
- 修改服务器配置文件里的
ee
子系统。您可以使用 JBoss CLI 或手动编辑这个文件。- 按照下列步骤使用 JBoss CLI 来修改服务器配置文件。
- 启动服务器并连接至管理 CLI。
- 对于 Linux,输入下列命令:
$ EAP_HOME/bin/jboss-cli.sh --connect
- 对于 Windows,输入下列命令:
C:\>EAP_HOME\bin\jboss-cli.bat --connect
您应该看到下面的结果:Connected to standalone controller at localhost:9999
- 要在
ee
子系统里创建myorg-conf
<global-modules> 元素,输入下列命令:/subsystem=ee:write-attribute(name=global-modules, value=[{"name"=>"myorg-conf","slot"=>"main"}])
您应该看到下面的结果:{"outcome" => "success"}
- 如果您向手动编辑服务器配置文件,请按照下列步骤进行。
- 停止服务器并打开服务器配置文件。如果您使用的是独立服务器,这个文件是
EAP_HOME/standalone/configuration/standalone.xml
,如果是受管域,这个文件是EAP_HOME/domain/configuration/domain.xml
。 - 找到
ee
子系统并为myorg-conf
添加全局模块。下面是ee
子系统元素的例子,已经进行修改并包含了myorg-conf
元素:<subsystem xmlns="urn:jboss:domain:ee:1.0" > <global-modules> <module name="myorg-conf" slot="main" /> </global-modules> </subsystem>
- 假设您复制了一个名为
my.properties
的文件到正确的模块位置,您现在可以使用下面的代码来加载属性文件了:Thread.currentThread().getContextClassLoader().getResource("my.properties");
3.1.4. 日志的修改
3.1.4.1. 修改日志依赖关系
JBoss LogManager 支持所有日志框架的前端,所以您可以保持现有的日志代码或移至新的 JBoss 日志框架。不管用哪种方法,因为模块化类加载有改变,您可能需要修改您的应用程序来添加所需的依赖关系。
过程 3.4. 更新程序日志代码
3.1.4.2. 为第三方日志框架更新应用程序代码
在 JBoss EAP 6 里,在默认情况下都已经添加了常见的第三方框架如 Apache Commons Loggin、Apache log4j、SLF4J 和 Java Logging 的日志依赖关系。在多数情况下,使用 JBoss EAP 容器提供的日志框架是更可取的。但是,如果您需要第三方框架提供的专有功能,您必须在部署里排除对应的 JBoss EAP 模块。请注意,虽然您的部署使用第三方的框架,服务器日志仍会继续使用 JBoss EAP 日志子系统配置。
org.apache.log4j
模块。第一个过程适用于所有的 JBoss EAP 6 版本,而第二个过程只适用于 JBoss EAP 6.3 及以后的版本。
过程 3.5. 配置 JBoss EAP 6 以使用 log4j.properties 或 log4j.xml 文件
注意
- 用下列内容创建一个
jboss-deployment-structure.xml
文件:<jboss-deployment-structure> <deployment> <!-- Exclusions allow you to prevent the server from automatically adding some dependencies --> <exclusions> <module name="org.apache.log4j" /> </exclusions> </deployment> </jboss-deployment-structure>
- 如果您在部署 WAR,请将
jboss-deployment-structure.xml
文件放入META-INF/
或WEB-INF/
目录;如果是部署 EAR,则请放入META-INF/
目录。如果您的部署包含了依赖的子部署,您必须在每个子部署里排除这些模块。 - 在 EAR 的
lib/
或 WAR 部署的WEB-INF/classes/
里包含log4j.properties
或log4j.xml
文件。如果您想将文件放到lib/
目录里,您必须在jboss-deployment-structure.xml
文件里指定<resource-root>
路径。<jboss-deployment-structure> <deployment> <!-- Exclusions allow you to prevent the server from automatically adding some dependencies --> <exclusions> <module name="org.apache.log4j" /> </exclusions> <resources> <resource-root path="lib" /> </resources> </deployment> </jboss-deployment-structure>
- 用下列 runtime 参数启动 JBoss EAP 6 服务器以防止在部署应用程序时控制台出现
ClassCastException
。-Dorg.jboss.as.logging.per-deployment=false
- 部署您的应用程序
过程 3.6. 配置 JBoss EAP 6.3 或更新版本的日志依赖关系
add-logging-api-dependencies
logging 系统属性来排除第三方的日志框架依赖关系。下面的步骤演示了在 JBoss EAP 独立服务器上如何修改这个 logging 属性。
- 用下列 runtime 参数启动 JBoss EAP 6 服务器以防止在部署应用程序时控制台出现
ClassCastException
。-Dorg.jboss.as.logging.per-deployment=false
- 打开终端窗口并连接至管理 CLI。
- 对于 Linux,输入下列命令:
$ EAP_HOME/bin/jboss-cli.sh --connect
- 对于 Windows,输入下列命令:
C:\>EAP_HOME\bin\jboss-cli.bat --connect
- 修改日志子系统里的
add-logging-api-dependencies
属性。这个属性控制容器是否添加隐性的 logging API 依赖关系到部署里。- 如果为
true
(默认值),将添加所有隐性的 logging API 依赖关系。 - 如果设置为
false
,依赖关系不会添加到部署里。
要排除第三方的日志框架依赖关系,您必须用下列命令设置这个属性为false
。/subsystem=logging:write-attribute(name=add-logging-api-dependencies, value=false)
这个命令添加了<add-logging-api-dependencies>
元素到standalone.xml
配置文件的logging
子系统里。<subsystem xmlns="urn:jboss:domain:logging:1.4"> <add-logging-api-dependencies value="false"/> .... </subsystem>
- 部署您的应用程序
3.1.4.3. 修改代码以使用新的 JBoss Logging 框架
要使用新的框架,请修改您的导入和代码:
过程 3.7. 修改代码和依赖关系以使用新的 JBoss Logging 框架
修改您的导入和日志代码
下面是一个使用新的 JBoss Logging 框架的例子:import org.jboss.logging.Level; import org.jboss.logging.Logger; private static final Logger logger = Logger.getLogger(MyClass.class.toString()); if(logger.isTraceEnabled()) { logger.tracef("Starting...", subsystem); }
添加日志依赖关系
包含 JBoss Logging 类的 JAR 位于名为org.jboss.logging
的模块。您的MANIFEST-MF
文件应该类似要:Manifest-Version: 1.0 Dependencies: org.jboss.logging
关于如何查找模块依赖关系的更多信息,请参考 第 3.1.2.3 节 “根据类加载的修改更新应用程序的依赖关系” and 第 4.2.1 节 “调试和解决移植问题”。
3.1.5. 应用程序包的修改
3.1.5.1. 修改 EAR 和 WAR 的打包
当您移植应用程序时,由于模块化类加载的修改,您可能需要修改 EAR 或 WAR 的打包结构。模块依赖关系是以特定的顺序加载的:
- 系统依赖关系
- 用户依赖关系
- 本地资源
- 部署间的依赖关系
过程 3.8. 修改归档的打包
打包 WAR
WAR 是一个模块,它里面的所有类都用相同的类加载器加载。这意味着打包在WEB-INF/lib/
目录里的类将和WEB-INF/classes
里的一样被对待。打包 EAR
EAR 由多个模块组成。EAR/lib/
目录是一个单个的模块且 EAR 里每个 WAR 或 EJB JAR 都是一个独立的模块。除非定义了显性的依赖关系,类不能访问 EAR 里其他模块里的类。子部署总是对父部署有着自动的依赖关系,这让它们可以访问EAR/lib/
目录里的类。然而,子部署并不总由自动的依赖关系来允许它们访问彼此。这个行为是通过设置ee
子系统配置里的<ear-subdeployments-isolated>
元素来控制的:<subsystem xmlns="urn:jboss:domain:ee:1.0" > <ear-subdeployments-isolated>false</ear-subdeployments-isolated> </subsystem>
在默认情况下,它被设置为 false,这允许子部署查看属于 EAR 里其他子部署的类。关于类加载的更多信息,请参考 https://access.redhat.com/site/documentation/JBoss_Enterprise_Application_Platform/ 上的《JBoss 开发指南》里的『类加载和模块』章节。
3.1.6. 数据源和资源适配器配置的修改
3.1.6.1. 根据配置的变化更新应用程序
- 如果您的应用程序使用了数据源,请参考: 第 3.1.6.2 节 “更新数据源配置”。
- 如果您的应用程序使用了 JPA 且捆绑了 Hibernate JAR,请参考下列移植选项: 第 3.1.6.4 节 “为 Hibernate 或 JPA 配置数据源”。
- 如果您的应用程序使用了资源适配器,请参考: 第 3.1.6.5 节 “更新资源适配器配置”。
- 关于如何配置基本安全性,请参考: 第 3.1.7.1 节 “应用程序安全性的修改”。
3.1.6.2. 更新数据源配置
在以前的 JBoss EAP 版本里,JCA 数据源配置在一个后缀为 *-ds.xml
的文件里定义。这个文件然后部署在服务器的 deploy/
下或和应用程序一起打包。JDBC 驱动会被复制到 server/lib/
目录或打包在应用程序的 WEB-INF/lib/
目录里。虽然这种配置数据源的方法仍被支持,我们不推荐在产品环境里使用它,因为 JBoss 的管理根据已不支持。
domain/configuration/domain.xml
文件里配置。如果 JBoss EAP 实例以独立服务器运行,那么数据源是在 standalone/configuration/standalone.xml file
里配置。以这种方式配置的数据源可以用 JBoss 管理接口(包括 Web 管理控制台和命令行接口)进行管理和控制。这些工具使得在受管域上管理部署和配置多个服务器更为容易。
JDBC 4.0 兼容的驱动可以作为部署或核心模块来安装。JDBC 4.0 兼容的驱动包含一个 META-INF/services/java.sql.Driver
文件,它制定驱动类名。非 JDBC 4.0 兼容的驱动需要其他的步骤。关于如何兼容 JDBC 4.0 驱动和更新您的数据源配置为 Web 管理控制台和 CLI 管理的配置,请参考 第 3.1.6.3 节 “安装和配置 JDBC 驱动”。
您可以使用 IronJacamar 工具来移植数据源和资源适配器配置。这个工具将 *-ds.xml
风格的配置文件转换为 JBoss EAP 6 所期望的格式。更多信息请参考 第 4.1.6 节 “使用 IronJacamar 工具来移植数据源和资源适配器配置”。
3.1.6.3. 安装和配置 JDBC 驱动
JDBC 驱动可以下列两种方式之一安装到容器里。
- 作为部署
- 作为核心模块
domain/configuration/domain.xml
文件里配置。如果 JBoss EAP 实例以独立服务器运行,那么数据源是在 standalone/configuration/standalone.xml file
里配置。Schema 引用信息两种模式都是一样的,您可以在 JBoss EAP 6 的 docs/schema/
里找到。我们在这里假设服务器是作为独立服务器运行的,而数据源是在 standalone.xml
文件里进行配置的。
过程 3.9. 安装和配置 JDBC 驱动
安装 JDBC 驱动。
将 JDBC 驱动作为部署安装。
这是我们推荐的安装驱动的方法。当 JDBC 驱动作为部署安装时,它会被部署为常规的 JAR。如果 JBoss EAP 实例作为独立服务器运行,请将兼容 JDBC 4.0 的 JAR 复制到EAP_HOME/standalone/deployments/
目录。对于受管域,您必须使用管理控制台或管理 CLI 将 JAR 部署到服务器组里。下面是一个安装为独立服务器的部署的 MySQL JDBC 驱动示例:$cp mysql-connector-java-5.1.15.jar
EAP_HOME/standalone/deployments/
任何兼容 JDBC 4.0 的驱动都自动会被承认且根据名称和版本安装至系统里。兼容 JDBC 4.0 的 JAR 都包含一个名为META-INF/services/java.sql.Driver
的文本文件,它指定驱动类的名称。如果这个驱动不兼容 JDBC 4.0,它可以用下列方法来部署:- 创建并添加
java.sql.Driver
文件到META-INF/services/
路径下的 JAR。这个文件应该包含驱动类的名称,例如:com.mysql.jdbc.Driver
- 在 deployment 目录里创建一个
java.sql.Driver
文件。对于作为独立服务器运行的 JBoss EAP 6 实例,这个文件应该位于:EAP_HOME/standalone/deployments/META-INF/services/java.sql.Driver
。如果服务器位于受管服务器,您必须使用管理控制台或管理 CLI 来部署这个文件。
这种方法的优点是:这种方法的缺点是:- 因为不需要定义模块,所以这是最简单的方法。
- 当服务器运行在受管域里时,使用这个方法的部署将自动传播到域里的所有服务器。这意味着管理员不需要手动分发这个驱动 JAR。
- 如果 JDBC 驱动由多个 JAR 组成,如驱动 JAR 以及依赖的许可证 JAR 或本地化 JAR,您不能将驱动安装为部署。您必须将其安装为核心模块。
- 如果这个驱动不兼容 JDBC 4.0,您必须创建一个包含驱动类名的文件并导入至 JAR 或覆盖到
deployments/
目录。
将 JDBC 驱动安装为核心模块。
要将 JDBC 驱动安装为核心模块,您必须在EAP_HOME/modules/
下创建一个文件路径结构。这个结构包含 JDBC 驱动 JAR,任何其他供应商许可证或本地化 JAR,以及一个定义模块的module.xml
文件。将 MySQL JDBC 驱动安装为核心模块
- 创建一个目录结构
EAP_HOME/modules/com/mysql/main/
- 在
main/
子目录里,创建一个包含下列为 MySQL JDBC 驱动定义的module.xml
文件:<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> </dependencies> </module>
模块名 “com.mysql”,映射了这个模块的目录结构。<dependencies>
元素用来指定这个模块对其他模块的依赖关系。在这种情况下,所有的 JDBC 数据源都依赖于在另一个名为javax.api
的模块里定义的 Java JDBC API。这个模块位于modules/system/layers/base/javax/api/main/
目录。注意
确保您在module.xml
文件的开头没有留下一个空格,否则您会遇到 "New missing/unsatisfied dependencies" 错误。 - 复制 MySQL JDBC 驱动 JAR 到
EAP_HOME/modules/com/mysql/main/
目录:$ cp mysql-connector-java-5.1.15.jar
EAP_HOME/modules/com/mysql/main/
将 IBM DB2 JDBC 驱动和 license JAR 安装为核心模块。
这个例子只是用来演示如何部署要求 JDBC Driver JAR 之外的 JAR 的驱动。- 创建目录结构
EAP_HOME/modules/com/ibm/db2/main/
。 - 在
main/
子目录里,创建一个包含下列用于 IBM DB2 JDBC 驱动和许可证的模块定义的module.xml
文件:<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="com.ibm.db2"> <resources> <resource-root path="db2jcc.jar"/> <resource-root path="db2jcc_license_cisuz.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
注意
确保您在module.xml
文件的开头没有留下一个空格,否则您会遇到 "New missing/unsatisfied dependencies" 错误。 - 复制 JDBC 驱动和 license JAR 到
EAP_HOME/modules/com/ibm/db2/main/
目录里。$ cp db2jcc.jar
EAP_HOME/modules/com/ibm/db2/main/
$ cp db2jcc_license_cisuz.jarEAP_HOME/modules/com/ibm/db2/main/
这种方法的优点是:这种方法的缺点是:- 当 JDBC 驱动由多个 JAR 组成时,这是唯一的途径。
- 用这个方法,不兼容 JDBC 4.0 的驱动可以无需修改驱动 JAR 或创建覆盖文件就进行安装。
- 通过设置模块要更为困难。
- 您必须手动将模块复制到运行在受管域里的每个服务器里。
配置数据源。
添加数据库驱动。
在相同的文件的<drivers>
元素了添加<driver>
元素。它也包含了之前的*-ds.xml
文件里定义的一些数据源信息。首先确定驱动 JAR 是否兼容 JDBC 4.0。兼容 JDBC 4.0 的 JAR 包含一个指定驱动类名的META-INF/services/java.sql.Driver
。这个服务器使用这个文件来在 JAR 里查找驱动类的名称。兼容 JDBC 4.0 的 JAR 不要求<driver-class>
元素,因为在 JAR 里它已被指定。下面是一个 JDBC 4.0 兼容的 MySQL 驱动的 driver 元素示例:<driver name="mysql-connector-java-5.1.15.jar" module="com.mysql"/>
不兼容 JDBC 4.0 的驱动要求一个<driver-class>
属性来确定驱动类,这是因为没有META-INF/services/java.sql.Driver
文件来指定驱动类名。下面是一个不兼容 JDBC 4.0 的 MySQL 驱动的 driver 元素示例:<driver name="mysql-connector-java-5.1.15.jar" module="com.mysql"> <driver-class>com.mysql.jdbc.Driver</driver-class></driver>
创建数据源。
在standalone.xml
文件的<datasources>
部分创建一个<datasource>
元素。这个文件包含之前的*-ds.xml
文件里定义的大部分数据源信息。重要
要使修改在服务器重启后仍然生效,您必须在编辑服务器配置文件前停止服务器。下面是standalone.xml
文件里的一个 MySQL 数据源元素示例:<datasource jndi-name="java:/YourDatasourceName" pool-name="YourDatasourceName"> <connection-url>jdbc:mysql://localhost:3306/YourApplicationURL</connection-url> <driver>mysql-connector-java-5.1.15.jar</driver> <transaction-isolation>TRANSACTION_READ_COMMITTED</transaction-isolation> <pool> <min-pool-size>100</min-pool-size> <max-pool-size>200</max-pool-size> </pool> <security> <user-name>USERID</user-name> <password>PASSWORD</password> </security> <statement> <prepared-statement-cache-size>100</prepared-statement-cache-size> <share-prepared-statements/> </statement> </datasource>
更新程序代码里的 JNDI 引用。
您必须在程序源代码里替换过时的 JNDI 查找名称以使用新的 JNDI 标准化数据源名称。详情请参考: 第 3.1.8.4 节 “修改应用程序以遵循新的 JNDI 命名规则”。您也必须让现有的访问数据源的@Resource
注解使用新的 JNDI 名称。例如:@Resource(name = "java:/YourDatasourceName").
3.1.6.4. 为 Hibernate 或 JPA 配置数据源
过程 3.10. 删除 Hibernate 捆绑
- 从您的应用程序的库目录里将 Hibernate JAR 删除。
- 当不再需要
<hibernate.transaction.manager_lookup_class>
元素时,在persistence.xml
里将其删除或注释。
3.1.6.5. 更新资源适配器配置
在以前的应用服务器版本里,资源适配器配置是在带有后缀 *-ds.xml
的文件里定义的。在 JBoss EAP 6 里,资源适配器是在服务器配置文件里配置的。如果您是在受管域里运行的,配置文件是 EAP_HOME/domain/configuration/domain.xml
。如果您运行的是独立服务器,配置文件是 EAP_HOME/standalone/configuration/standalone.xml
。Schema 引用信息两种模式都是一样的,您可以在 Iron Jacamar 网站 http://www.ironjacamar.org/documentation.html 的 Schemas 里找到。
重要
资源适配器描述符信息是在服务器配置文件中的下列 subsystem 元素里定义的:
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.1"/>您将使用资源适配器
*-ds.xml
文件里定义的相同的一些信息。
<resource-adapters> <resource-adapter> <archive>multiple-full.rar</archive> <config-property name="Name">ResourceAdapterValue</config-property> <transaction-support>NoTransaction</transaction-support> <connection-definitions> <connection-definition class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleManagedConnectionFactory1" enabled="true" jndi-name="java:/eis/MultipleConnectionFactory1" pool-name="MultipleConnectionFactory1"> <config-property name="Name">MultipleConnectionFactory1Value</config-property> </connection-definition> <connection-definition class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleManagedConnectionFactory2" enabled="true" jndi-name="java:/eis/MultipleConnectionFactory2" pool-name="MultipleConnectionFactory2"> <config-property name="Name">MultipleConnectionFactory2Value</config-property> </connection-definition> </connection-definitions> <admin-objects> <admin-object class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleAdminObject1Impl" jndi-name="java:/eis/MultipleAdminObject1"> <config-property name="Name">MultipleAdminObject1Value</config-property> </admin-object> <admin-object class-name="org.jboss.jca.test.deployers.spec.rars.multiple.MultipleAdminObject2Impl" jndi-name="java:/eis/MultipleAdminObject2"> <config-property name="Name">MultipleAdminObject2Value</config-property> </admin-object> </admin-objects> </resource-adapter> </resource-adapters>
3.1.7. 安全性的修改
3.1.7.1. 应用程序安全性的修改
在以前的 JBoss EAP 版本里,放在 EAP_HOME/server/SERVER_NAME/conf/
下的属性文件位于 classpath 上且可以轻易地被 UsersRolesLoginModule
找到。在 JBoss EAP 6 里,目录结构已经发生了变化。属性文件必须打包在应用程序里,使其在 classpath 上可用。
重要
standalone/configuration/standalone.xml
或 domain/configuration/domain.xml
服务器配置文件里的 security-domains
下添加一个新的安全域:
<security-domain name="example"> <authentication> <login-module code="UsersRoles" flag="required"> <module-option name="usersProperties" value="${jboss.server.config.dir}/example-users.properties"/> <module-option name="rolesProperties" value="${jboss.server.config.dir}/example-roles.properties"/> </login-module> </authentication> </security-domain>
${jboss.server.config.dir}
指向 EAP_HOME/standalone/configuration/
目录。如果它运行在受管域里, ${jboss.server.config.dir}
指向 EAP_HOME/domain/configuration/
目录。
在 JBoss EAP 6 里,安全域名称里不再使用前缀 java:/jaas/
。
- 对于 Web 应用程序,您必须从
jboss-web.xml
里的安全域配置里删除这个前缀。 - 对于企业级应用程序,您必须从
jboss-ejb3.xml
里的安全域配置里删除这个前缀。这个文件已经替换了 JBoss EAP 6 里的jboss.xml
。
3.1.7.2. 更新使用 PicketLink STS 和 Web Services 的应用程序
如果您的 JBoss EAP 6.1 应用程序使用了 PicketLink STS 和 Web service,在移植到 JBoss EAP 6.2 或更新版本时您需要进行一些修改。我们修复了 JBoss EAP 以解决 CVE-2013-2133,在运行任何附加到基于 EJB3 的 WS 端点的 JAXWS 处理程序前它强制执行容器的授权检查。因此,一些 PicketLink STS 功能会受到影响,因为 PicketLink SAML2Handler
会建立一个安全性主体在以后使用。您可能在服务器日志里看到 NullPointerException
,因为当HandlerAuthInterceptor
访问 SAML2Handler
时这个主体是 NULL
。要修复这个问题,您必须要禁用安全检查。
过程 3.11. 禁用额外的授权检查
- 您可以禁用额外的授权检查并通过下列方法之一坚持使用现有的 PicketLink 部署。
设置系统属性
您可以通过设置org.jboss.ws.cxf.disableHandlerAuthChecks
属性为true
来禁用服务器级别的额外授权检查。这个方法会影响应用服务器上的所有部署。关于设置系统属性的信息,请参考《管理和配置指南》里的 『用管理 CLI 配置系统属性』。在部署的 Web 服务描述文件里创建一个属性
您可以通过设置jboss-webservices.xml
文件里的org.jboss.ws.cxf.disableHandlerAuthChecks
属性为true
来禁用部署级别的额外授权检查。这个方法只会影响专有的部署。- 在您要禁用额外授权检查的部署的
META-INF/
目录里创建一个jboss-webservices.xml
文件。 - 添加下列内容:
<?xml version="1.1" encoding="UTF-8"?> <webservices xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee"> <property> <name>org.jboss.ws.cxf.disableHandlerAuthChecks</name> <value>true</value> </property> </webservices>
注意
org.jboss.ws.cxf.disableHandlerAuthChecks
属性会让系统易受 CVE-2013-2133 攻击。如果应用程序期望应用 EJB 方法上声明的安全限制且不独立于 JAX-WS 处理程序进行应用,那这个属性不应该启用。这个属性只能用于向后兼容的目的来避免破坏应用程序。
3.1.8. JNDI 的修改
3.1.8.1. 更新应用程序 JNDI 命名空间的名称
EJB 3.1 引入了一个标准化的全局 JNDI 命名空间和一系列相关的映射到不同 Java EE 应用程序作用域的命名空间。可移植 EJB 名称只能绑定其中三种:java:global
、java:module
和 java:app
。使用 JNDI 查找的应用程序必须进行修改以遵循新的标准化 JNDI 命名空间规则。
过程 3.12. 修改 JNDI 查找
前一版本里的 JNDI 命名空间示例以及如何在 JBoss EAP 6 里指定可以在这里找到: 第 3.1.8.5 节 “以前版本的 JNDI 命名空间示例和它们在 JBoss EAP 6 里是如何指定的”
3.1.8.2. 可移植的 EJB JNDI 名称
Java EE 6 规格定义了 4 种逻辑命名空间,每种都有自己的作用域,但可移植的 EJB 名称只能绑定到其中三种。下表详述了何时和如何使用每种命名空间。
表 3.1. 可移植的 JNDI 命名空间
JNDI 命名空间 | 描述 |
---|---|
java:global |
这个命名空间里的名称是应用程序服务器实例里部署的所有应用程序共享的。您可以使用这个命名空间里的名称来查找部署到相同服务器里的 EJB 外部归档。
下面是一个 java:global 命名空间的示例:
java:global/jboss-seam-booking/jboss-seam-booking-jar/HotelBookingAction
|
java:module |
这个命名空间里的名称是由部署在模块里的所有组件共享的,例如单一 EJB 模块或 web 模块中所有组件里的所有 EJB。
下面是一个 java:module 命名空间的示例:
java:module/HotelBookingAction!org.jboss.seam.example.booking.HotelBooking
|
java:app |
这个命名空间里的名称是由单个应用程序里的所有模块里的所有组件共享的,例如相同 EJB 文件里的 WAR 或 EJB JAR 文件将可以访问 java:app 命名空间里的资源。
下面是一个 java:app 命名空间的示例:
java:app/jboss-seam-booking-jar/HotelBookingAction
|
3.1.8.3. 复核 JNDI 命名空间规则
JBoss EAP 6 已经改进了 JNDI 命名空间,不只是为应用服务器里绑定的每个名称提供可预测和一致的规则,也防止了将来的兼容性问题。这意味着如果名称不遵循新的规则,应用程序里的当前命名空间也会出现问题。
- 未限定的相对名称如
DefaultDS
或jdbc/DefaultDS
应该根据上下文限定于java:comp/env
、java:module/env
或java:jboss/env
。 - 未限定的
绝对
名称如/jdbc/DefaultDS
应该限定于java:jboss/root
。 - 限定的
绝对
名称如java:/jdbc/DefaultDS
应该和上面未限定的绝对
名称采用相同的方式进行限定。 java:jboss
命名空间在整个 AS 服务器实例间进行共享。- 带有
java:
前缀的相对
名称必须位于下列 5 个命名空间中的一个:comp
、module
、app
、global
或私有的jboss
。任何以java:xxx
开始的名称里的 xxx 不匹配上面的 5 个命名空间都将导致无效名称错误。
3.1.8.4. 修改应用程序以遵循新的 JNDI 命名规则
- 下面是一个 JBoss EAP 5.1 里的 JNDI 查找示例。这些代码是在一个初始方法里找到的。
private ProductManager productManager; try { context = new InitialContext(); productManager = (ProductManager) context.lookup("OrderManagerApp/ProductManagerBean/local"); } catch(Exception lookupError) { throw new ServletException("Unable to find the ProductManager bean", lookupError); }
请注意查找名称是OrderManagerApp/ProductManagerBean/local
。 - 下面是在 JBoss EAP 6 里如何用依赖关系注入编写相同查找的示例:
@EJB(lookup="java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager") private ProductManager productManager;
查找值现在被定义为成员变量并使用新的可移植的java:app
JNDI 命名空间名java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager
。 - 如果您不想使用依赖关系注入,您仍可以像上面那样创建新的 InitialContext 并修改查找以使用新的 JNDI 命名空间名称。
private ProductManager productManager; try { context = new InitialContext(); productManager = (ProductManager) context.lookup("java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager"); } catch(Exception lookupError) { throw new ServletException("Unable to find the ProductManager bean", lookupError); }
3.1.8.5. 以前版本的 JNDI 命名空间示例和它们在 JBoss EAP 6 里是如何指定的
表 3.2. JNDI 命名空间映射表
JBoss EAP 5.x 里的命名空间 | JBoss EAP 6 里的命名空间 | 其他注释 |
---|---|---|
OrderManagerApp/ProductManagerBean/local | java:module/ProductManagerBean!services.ejb.ProductManager | Java EE6 标准绑定。作用域为当前模块,只可以在相同模块里访问。 |
OrderManagerApp/ProductManagerBean/local | java:app/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager | Java EE6 标准绑定。作用域为当前应用程序,只可以在相同应用程序里访问。 |
OrderManagerApp/ProductManagerBean/local | java:global/OrderManagerApp/OrderManagerEJB/ProductManagerBean!services.ejb.ProductManager | Java EE6 标准绑定。作用域为应用服务器,可全局访问。 |
java:comp/UserTransaction | java:comp/UserTransaction | 命名空间作用域为当前组件。非 Java EE 6 的线程不可访问,例如您的应用程序直接创建的线程。 |
java:comp/UserTransaction | java:jboss/UserTransaction | 可全局访问,如果 java:comp/UserTransaction 不可用则使用它。 |
java:/TransactionManager | java:jboss/TransactionManager | |
java:/TransactionSynchronizationRegistry | java:jboss/TransactionSynchronizationRegistry |