您的位置:首页 > 其它

从JBOSS启动的问题谈及JBOSS中jar的加载顺序

2017-12-15 13:57 411 查看
JBOSS启动的问题解决到CLASSLOADER在JBOSS的载入

一,问题

最近使用JBOSS做WEB开发的容器,发布本地的一个应用的时候,发现在日志中总是报错,此应用也启动不起来,具体的日志如下:

E

Java代码


RROR context.ContextLoader - Context initialization failed

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from relative location [common/webx-root.xml]

Offending resource: ServletContext resource [/WEB-INF/webx.xml]; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/common/webx-root.xml]; nested exception is java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionAttributes(Lorg/w3c/dom/Element;Ljava/lang/String;Lorg/springframework/beans/factory/config/BeanDefinition;Lorg/springframework/beans/factory/support/AbstractBeanDefinition;)Lorg/springframework/beans/factory/support/AbstractBeanDefinition;

Caused by:

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/common/webx-root.xml]; nested exception is java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionAttributes(Lorg/w3c/dom/Element;Ljava/lang/String;Lorg/springframework/beans/factory/config/BeanDefinition;Lorg/springframework/beans/factory/support/AbstractBeanDefinition;)Lorg/springframework/beans/factory/support/AbstractBeanDefinition;

Caused by:

java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionAttributes(Lorg/w3c/dom/Element;Ljava/lang/String;Lorg/springframework/beans/factory/config/BeanDefinition;Lorg/springframework/beans/factory/support/AbstractBeanDefinition;)Lorg/springframework/beans/factory/support/AbstractBeanDefinition;

一层层的看日志信息:

直接的错误信息是说不能加载相关的bean对象,然后继续看,为什么呢?说是在加载webx-root.xml的时候出错,然后继续看:

说是:

Java代码


java.lang.NoSuchMethodError: org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionAttributes(Lorg/w3c/dom/Element;Ljava/lang/String;Lorg/springframework/beans/factory/config/BeanDefinition;Lorg/springframework/beans/factory/support/AbstractBeanDefinition;)Lorg/springframework/beans/factory/support/AbstractBeanDefinition;

这段呢,说是没有这样的方法:parseBeanDefinitionAttributes,这个可是SPRING里面的啊,然后去网上搜索了一下,大致得到的结论有:

1.是配置文件错误---仔细分析日志就知道,不是这样的。

因为一直对JBOSS不是很熟悉,以前用TOMCAT做开发比较多,所以开始就没有想到部署的包有问题。因为同样的war包在别的地方是OK的。

说明还是我这里的问题。

2.继续查找,还是回头来仔细分析日志,发现最终还是spring报的错误,联想到这个具体的信息,猜测可能是spring的包出问题了。

可是应用里面的包都是OK的啊?那肯定是我环境的问题了。

原因:

然后去研究JBOSS的目录,发现JBOSS每次发布的时候都会生成一些临时文件到\server\default\tmp\deploy下面去,每次我发布的时候也都清除一下。

会不会是缓存出了问题?仔细查找这个临时目录下的文件,发现发布之后,生成了一个tmp3853123996149741254spring-2.0.7.jar的文件,而我确认我的应用需要的SPRING的版本是2.5.6,到这里终于恍然大悟:发布之后我的应用采用的是这个2.0.7的spring包,而不是我的应用WEB-INF\lib下面的。

那这个包是哪里生成的?仔细查找,发现在\server\default\deploy\jboss-spring-jdk5.deployer目录下就有一个。

而JBOSS的机制就是,发布的时候将\server\default\deploy下面的一些基础的应用一起发布,而这些基础应用里面包括上面的spring发布在temp的临时目录下,是作为所有应用的基础包,也就是说这些包的优先级要高于每个普通应用的包的。

解决的方法也很简单:

替换掉\server\default\deploy\jboss-spring-jdk5.deployer目录下的spring-2.0.7.jar为新的spring-2.5.6.jar即可。

注:我用的JBOSS版本是4.2.2GA.

二,JBOSS的加载机制

下面就来简单讲解一下JBOSS的JAR加载顺序:

1) org.jboss.Main.main(String[]) 为入口.

2) main 函数创建一个名叫”jboss”的线程组, 然后创建一个属于该组的线程, 在线程中执行boot方法.

3) boot 方法首先处理main函数中的参数(及一些其它的系统环境设置), 接着就用系统的属性创建了org.jboss.system.server.ServerLoader实例[new ServerLoader(props)].

4) ServerLoader 注册Jboss相关的类路径, 包括XML解析器, jboss-jmx.jar, concurrent.jar及其它的一些额外的类路径.

这里一般都是在JBOSS_HOME\lib下面的jar.

5) ServerLoader 通过load(ClassLoader)方法创建Jboss Server实例. 参数ClassLoader是ClassLoader parentCL = Thread.currentThread(). getContextClassLoader( )得到的当前线程的类加载器. 创建的Server实例是org.jboss.system.server.Server接口的实现.
load(ClassLoader)方法的细节:

 用jar包及在ServerLoader中注册的类路径创建一个URLClassLoader的实例, 把传入的ClassLoader作为该URLClassLoader的parent.

 Server 接口的实现类由系统属性 jboss.server.type决定, 默认是 org.jboss.system.server.ServerImpl.

 URLClassLoader 通过无参构造函数加载Server接口实现的实例. 在加载前把当前线程的类加载器置为该URLClassLoader, 在加载完成后再置回之前传入的ClassLoader.

6) Server 实例用系统属性进行初始化[server.init(props)].

7) 服务起动[server.start()]. 起动过程的默认实现如下:

 把当前线程类型加载器置为加载该Server接口实现实例的ClassLoader.

 在jboss域内, 通过MBeanServerFactory的createMBeanServer(String)方法创建MbeanServer实例.

 在MBean Server上注册ServerImpl和ServerConfigImpl两个MBean.

 初始化统一的类加载仓库(unified class loader repository), 用来装载服务器配置目录及其它可选目录下的jar文件. 对于每一个jar文件和类目录都会创建一个相应的org.jboss.jmx.loading.UnifiedClassLoader实例, 并且注册到统一的仓库中. 其中一个UnifiedClassLoader实例会被设置为当前线程上下文的ClassLoader.
[?: This effectively makes allUnifiedClassLoaders available through the thread context class loader.]

 接下来创建org.jboss.system.ServiceController的MBean实例. ServiceController管理JBoss MBean服务的生命周期.

需要注意的是:JBOSS在加载自带的核心JAR之后,将会优先加载下面的两个目录

1、D:\jboss\server\default\lib

2、D:\jboss\server\default\tmp\deploy

其中1会在2之前加载,而目录2是发布某个WAR,EAR,EJB等应用之后生成的临时的jar,这些应用的所有JAR会生成诸如temp*.jar的形式。本文开头提到的错误也就是在目录1中存在一个spring.jar的包,优先于各个应用的spring.jar包。

原文:http://scholers.iteye.com/blog/821402
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: