从Jboss5迁移到Jboss7
1. Jboss7新特性
1.1 构建在Modular Service Container上,充分地利用了多核处理器的能力,并发、按需启动服务,启动速度更快、占用内存更小。
1.2 全面兼容Java EE6
1.3 支持JDK6/7
1.4 统一的配置和管理
1.5 兼容OSGI 4.2,支持OSGI和Java EE组件模型集成。
1.6容易测试:利用Arquillian测试平台—一种集成测试组件模型,更易于测试,改变-编译-测试的周期更短。
1.7 两种模式
Standalone模式(使用standalone.bat启动)相当于以前的3、4、5、6版本。配置文件、发布内容等放在standalone目录下。
Domain模式(使用domain.bat启动)是Jboss7的一个新特征,可以在一个控制点管理多个服务器。
1.8 类加载
类加载基于Jboss Module,取代了层次类加载环境,避免了当类存在多个版本时,导致类加载错误。由于类加载是基于模块的,必须显示的定义模块依赖。部署也是模块化的,如果没有显示的定义类依赖则不能访问应用服务器jar中的类。
2. 迁移步骤
在Jboss7部署项目与在jboss5上有很大区别,最主要原因是由于类的加载模式改变了。Jboss5部署相对简单,只需将相应的包部署到lib和deploy目录即可,类加载器会按层次自动加载,不用配置依赖关系。而jboss7完全不一样,jboss7是按模块化加载,不同模块由不同类加载器加载,其他模块的jar包,对其是不可见的,这时需要手动配置包之间依赖关系,否则会报ClassNotFoundException等错误。另外对于数据源和JNDI的配置也发生了变化,所以把项目从Jboss5往Jboss7迁移时可以大概分为下述3个步骤:
2.1 依赖关系的配置
在Jboss7中,模块之间的依赖关系分为隐式依赖和显式依赖。
2.1.1隐式依赖
尽管Jboss7中模块默认是隔离的,在部署过程中,一些由应用服务器定义的模块依赖会自动装配。例如,如部署一个Java EE应用,将自动添加Java EE API依赖,这也称为隐式模块依赖。
2.1.2显式依赖
对于显式依赖,必须在MANIFEST.MF文件的“Dependencies:”或“Class-Path:”项或在Jboss7特有的部署文件jboss-deployment-structure.xml中显式定义。对于已有的项目,手动去查找各个模块之间的依赖关系是费时又费力的,可以通过Tattletale工具来分析,在分析报告的OUTPUT_DIRECTORY/index.html文件中点击"JBoss A7"则可以得到部分依赖关系,另外的依赖关系可以在“Depends On”中得到。
在Jboss7中类的加载优先级(从高到低):
(1)系统依赖- 服务器自动加载的模块依赖,包括Java EE api。
(2)用户依赖- 在jboss-deployment-structure.xml(在ear的META-INF内,war的META-INF或WEB-INF内)或Dependencies:项内配置的依赖。
(3)本地资源- 发布目录下的类文件,如war包下的WEB-INF/classes或WEB-INF/lib。
(4)部署间依赖- 在ear内的其他部署依赖。包括ear lib目录内的类,或其他ejb包内的类。
在部署时,War包被认为是一个单独的模块,WEB-INF/lib和WEB-INF/classes内的类是相同的,都由同一类加载器加载。Ear包是多模块的部署。这意味着不是ear内的所有类都能访问ear内所有其他类,除非指定明确的依赖。默认情况下,EAR/lib目录是一个单独的模块,每个WAR或EJB jar是一个单独的模块。子部署(war和ejb-jar)总是依赖父模块,可以访问EAR/lib内的类,然而它们彼此间不总是有自动依赖。可以通过修改如下配置控制这个行为:
<subsystem xmlns="urn:jboss:domain:ee:1.0" >
<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
</subsystem>
ear-subdeployments-isolated默认值为false,允许子部署访问其他子部署的类。在一个Ear包中,war可以访问jar包里的类,jar包之间也可以相互访问,但是jar包不能访问war包中的类,不管ear-subdeployments-isolated的值为true还是false。
2.1.3全局模块
可以把一些模块设置为全局模块,则所有的部署都可以访问该模块,在做项目迁移时,可以使用这种方法来解决模块依赖问题。格式如下:
<subsystem xmlns="urn:jboss:domain:ee:1.0"/>
<global-modules>
<module name="org.apache.log4j"/>
</global-modules>
2.2 数据源配置
在Jboss5中,数据源的配置文件为*-ds.xml文件,该文件放在服务器的deploy目录下,其相应的JDBC驱动则放在服务器的lib目录或应用程序的WEB-INF/lib目录下。而在Jboss7中这些都不需要,配置文件为Jboss7_home/standalone/configuration/standalone.xml或者是Jboss7_home/domain/configuration/domaion.xml。可以使用IronJacamar工具把原来的*-ds.xml文件转变为Jboss7中所需要的格式。
2.2.1 安装JDBC驱动
安装JDBC驱动分为两种方式:(1)作为一个部署(推荐的做法)(2)作为一个模块
2.2.1.1 作为一个部署
直接把JDBC驱动作为一个普通的jar包放在deployment目录下,该JDBC驱动应该是一个兼容JDBC4(Jdbc 4兼容的driver在jar包内含有META-INF/services/java.sql.Driver文件,其中指定了驱动类名称。)的驱动。若JDBC驱动包含不止一个jar包,则应作为一个模块来部署。
2.2.1.2 作为一个模块
需要在modules目录下创建一个目录结构,其内包含驱动jar包和module.xml文件。下面以安装mysql驱动为例,首先在modules目录下建立com/mysql/main文件夹,且把mysql驱动和module.xml文件放在main文件夹中。module.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql">
<resources>
<resource-root path="mysql-connector-java-5.1.15.jar"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
需要注意的是name应与建立的文件夹同名且module.xml文件的开头不能有空格,否则会产生“New missing/unsatisfied dependencies”错误。
2.2.2 注册JDBC驱动
2.2.2.1 作为模块的JDBC驱动注册
<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>
2.2.2.2 作为部署的JDBC驱动注册
<datasource jndi-name="java:/MySqlDS" pool-name="MySqlDS" enabled="true" use-java-context="true">
<connection-url>jdbc:mysql://localhost:3306/gg</connection-url>
<driver>mysql</driver>
<pool>
<min-pool-size>20</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>true</prefill>
</pool>
<security>
<user-name>root</user-name>
<password>111</password>
</security>
<driver name="mysql" module="com.mysql">
<driver-class>com.mysql.jdbc.Driver</driver-class>
</driver>
</datasources>
2.3 JNDI
2.3.1 JNDI命名规则
jboss7使用了更为严格的JNDI命名规则,其基本规则如下:
(1)相对命名如“ExampleDS”或“jdbc/ExampleDS”应该修改为相对于具体环境,如“java:comp/env”,“java:jboss/env”,“java:module/env”等。
(2)绝对命名如“/jdbc/ExampleDS”应该修改为相对命名如“java:jboss/root”。
(3)如“java:/jdbc/ExampleDS”的绝对命名也应如(2)修改。
(4)“java:jboss”命名在整个jboss服务器中时共享的。
(5)任何以“java:”开头的命名必须结合“comp”,“module”,“app”,“global”,“jboss”中的一个,否则会报错。
2.3.2 Local JNDI
name |
scope |
properties |
java:comp |
current component |
standard namespaces |
java:module |
current module |
|
java:app |
current application |
|
java:global |
application server |
|
java:jboss |
global |
jboss7 提供的全局命名 |
java:/ |
global |
|
java:jboss/exported |
global |
如在HelloWorldEar包中有HelloWorldEJB,在HelloWorldEJB中有HelloWorld bean实现了HelloWorldRemote接口,则部署时HelloWorld绑定的JNDI为以下几个:
java:global/HelloWorldEar/HelloWorldEJB/HelloWorld!com.ejb.HelloWorldRemote
java:app/HelloWorldEJB/HelloWorld!com.ejb.HelloWorldRemote
java:module/HelloWorld!com.ejb.HelloWorldRemote
java:jboss/exported/HelloWorldEar/HelloWorldEJB/HelloWorld!com.ejb.HelloWorldRemote
java:global/HelloWorldEar/HelloWorldEJB/HelloWorld
java:app/HelloWorldEJB/HelloWorld
java:module/HelloWorld
2.3.3 remote JNDI
在jboss5中默认ejb的JNDI名称为:
本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local
远程接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote
如果ejb只是在单独的jar包中,则不需要EAR-FILE-BASE-NAME。而在jboss7中remote ejb的JNDI命名规则如下:
ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>,如果是有状态bean,则还需加上?stateful。
其中app-name指的是ear包的名称
module-name指的是其所在的jar包的名称
distinct-name指的是起的别名
bean-name指的是该bean的名字
fully-qualified-classname-of-the-remote-interface指的是其实现的接口的名字,要加上完整的包名。
2.3.4 绑定全局JNDI
直接修改standalone.xml或者domain.xml文件,格式如下所示:
<subsystem xmlns="urn:jboss:domain:naming:1.1"/>
<bindings>
<lookup name="AdminEjb/local" lookup="ejb:/admin_ejb/AdminEjb!com.mipt.admin.ifc.AdminIfc"/>
</bindings>
3. 可能会遇到的问题
3.1ejb JNDI
由于jboss7与jboss5JNDI命名方式的差别很大,若在原有项目中大量使用了JNDI,则在迁移时要进行更改或绑定,将是一项庞大的工程。
3.2 配置文件无法解析
在添加数据源或其他需要修改standalone.xml或domain.xml配置文件后,重新启动服务器会报无法解析配置文件的错误,可以通过jboss-home/bin/jboss-cli.bat来修该配置文件。以下为添加一个数据源的格式:
[standalone@localhost:9999 /] /subsystem=datasources:installed-drivers-list
{
"outcome" => "success",
"result" => [{
"driver-name" => "h2",
"deployment-name" => undefined,
"driver-module-name" => "com.h2database.h2",
"module-slot" => "main",
"driver-xa-datasource-class-name" => "org.h2.jdbcx.JdbcDataSource",
"driver-class-name" => "org.h2.Driver",
"driver-major-version" => 1,
"driver-minor-version" => 2,
"jdbc-compliant" => true
}]
3.3 ClassNotFoundException ClassCastException
出现上述问题则是模块之间缺少依赖关系,导致找不到相应的类。
总结
在把项目从jboss5迁移到jboss7上时,上述3个步骤能解决大部分的问题。对于日志依赖的配置以及使用了spring、hibernate、EJB2技术的项目迁移的更改还需做另外的探讨。以上为个人总结,欢迎大家拍砖。