理解类加载器:J2EE环境下的log4j

转自http://blog.csdn.net/yjq8116/article/details/4498624
  大纲

  Log4j是个很流行的日志记录工具。根据java项目不同的日志需求和调试需求。他能够提供很灵活的控制。他能够对输出信息进行分级控制。也能够在运行时改变输出信息的表现格式。而这一切都无需改变源程式。

  Log4j用三个对象来控制日志的记录。Logger,appenders,和layouts。logger会以特定的layouts(样式)将日志记录到appenders中。在这个操作过程中常常需要指定具体的外部配置文档。(指定外部配置文档也是最好的一种方式)。这些配置信息会在您的应用开始时加载进来,也可能在运行的时候被改变。

  在使用log4j的时候将会用到以下这些步骤:

  1.写配置文档,在文档中需要:

  • 指定root logger的级别并且和一个appender绑定

  • 指定appender的属性

  • 为appender指定一个layout

  2.在您的代码中,需要根据class或name得到一个logger.典型的一种做法是将logger

  和当前的类的进行关联。

  3.用您从第二步得到的logger的任何一种方法(log.debug(),log.info(),log.warn

  (),log.error())进行写日志。

  配置安装

  在这本书的例子是运行在weblogic 7.0 sp2 demo上。我们之所以用weblogic代替开源的产品(如jboss)是因为weblogic为在项目组中配置log4j提出了更多的挑战。他也是最流行的应用服务器。自从我发表的之前的文章。我收的绝大多数问题都是关于他的。但是这里决不是暗示推荐使用weblogic。这只是提供一个测试环境。说明在j2ee环境下怎样配置log4j

  Weblogic的配置安装

  Weblogic7.0sp2能够从BEA’s trial page下载。选择您需要的版本类型进行下载。注意您必须要在bea上面进行一些个人信息的注册。而且下载的文档很巨大。大约有150M。当然您也有别的选择。您能够选择免费的测试CD

  假如您得到了安装文档。安装就很简单了。您只需要按照安装向导一步一步安装就能够了。我们的测试环境选择典型安装。当安装到最后,安装向导会问您是否需要配置Domain.选择yes然后就会运行Domain的配置向导。第一屏、选择Domain的类型和名字。选择WLSDomain作为Domain的类型,给他起个名字叫mydomain.第二屏、配置server的类型为单一server(standalone server).再下一屏选择缺省路径做为Domain的路径,再点击next为server进行配置。然后一路next就能够了。最后需要您为domain输入管理员帐号和密码。我一般就是以admin作为管理员帐号,password最为密码(很原始的做法)。接下来选择是否将service注册成windows的services(在windows环境下安装),一般选择no。最后选择yes在windows开始菜单上方置快捷方式。最后点击create建立Domain.

  运行weblogic就很简单了。从开始菜单Start->All Programs->BEA WebLogic Platform 7.0->User Projects->mydomain->Start Server这样能够启动server.但是更常用的方式是从dos命令行,进入BEA的HOME目录。进入user_projects\mydomain后,运行startWebLogic.cmd.就能够了。启动的时候会需要您输入管理员帐号和密码。最后您能够看到server开始启动。当您看到Server start in running mode表示启动成功。假如要关闭您只要关闭Dos窗口就能够了。

  假如您安装运行成功。您能够在浏览器中输入如下地址http://localhost:7001/console.您会进入webogic的管理界面。您能够对applications和server进行各种配置。当然您要输入管理员帐号和密码。就和启动时输入的相同。进入后您能够看到各种管理任务的界面。您也能够执行相应的管理任务。

  log4j的安装

  和前面提到的相同。Log4j能够从log4j web site.下载。请按照前面的文章介绍进行下载和安装log4j的二进制代码。在这章最后我们会介绍log4j的配置。

  类加载器的概念有什么不相同。

  虽然有关类加载器的讨论在本文以外已有很多了。但是我还是尽力解释一下类加载器是怎样影响应用服务器中log4j的配置的。

  类加载器。顾名思义,表示在java虚拟机中加载calsses.在我们的class执行和被访问之前。他必须通过类加载器加载使之有效。给定一个class名字,类加载器会定位class并且将他加载到java虚拟机。但是类加载器本事就是class。这就带来一个问题。是谁来加载这些类加载器呢。

  当您运行一个java程式。(例如在命令行内输入java命令),他就会执行并且启动一个本地的native java launcher(我叫他java 启动者,估计不太准确注明一下)。这里本地的意思是指针对您的平台和运行环境而言。这个本地的java启动者包含一个类加载器,这个类加载器的名字叫做bootstrap 类加载器.(引导类加载器).这个引导类加载器.是本地的和您的环境有关。而且他不是用java写成的。这个引导类加载器的主要功能是加载java的核心类。


  

Figure 1; 类加载器 委托层次



  Java虚拟机缺省会执行其他两个类加载器.引导类加载器会加载extension(扩展)类加载器和application(应用)类加载器到内存中。这些都是用java写成的。和前面提到的相同。引导类加载器会加载java的核心类(例如:java.util包下的类)。扩展类加载器会加载扩展的java核心类(例如:javax.包下的类,或是在运行环境中类路径ext目录下的java类。)应用类加载器会加载您应用下的各种class文档。

  任何三种类加载器都遵循委托模式。当低一级的类加载器需要定位一个类。他会将这个任务委托给父一级类加载器.当您的应用需要一个特别的类。应用类加载器会将这个任务委托给扩展类加载器.而扩展类加载器又会将这个任务委托个引导类加载器.。假如您请求的类是个核心类。那么引导类加载器会将这个类加载,使您能够使用这个类。但是假如很难找到这个类。这个请求就会返回到扩展类加载器.最后在返回到应用类加载器.这样的做法就使每个类加载器会先让他的父一级的类加载器搜索需要的类。只有当父一级的类加载器没有找到。才会让子一级的类加载器为他自己搜索所需的类。

  在应用服务器当中,每一个单独部署的web应用和EJB都会取得属于自己的类加载器(正常情况下,这也是weblogic的处理方式)。这种类加载器来源于应用类加载器.他们主要用来加载特定的ejb和web应用。(注意一点,当我们的web应用打包成ear文档??ejb和webapps的混合,这时候只会有一个类加载器,不会再分成ejb和webapp两种)这种新的类加载器会加载任何webapp和ejb所需要的类包。当然首先这些类包不存在于java核心类中和扩展类中(ext)。他能够加载也能够卸载类包。但他有一种缺省类加载器所没有的特性。这个特性就是能够对应用进行热部署。

  当weblogic启动的时候。他会用java提供的应用类加载器加载相应的类。并且构造相应的运行环境。然后他会启动特定的类加载器.这种特定的类加载器来源于java的应用类加载器.java的应用类加载器会为特定的类加载器加载相应的classes.这种特定的类加载器对于其他的应用的类加载器是不可见。因此。一个特定应用所加载的classes.对于其他应用是不可见的。

  



Figure 2: 特定的应用 类加载器



  那么我们怎样使一个单独的类对任何的应用都起作用呢。只有使用上层的类加载器.能够把这个类方在weblogic中classpath里面。当weblogic启动的时候。缺省的java 应用类加载器会自动把类加载到内存中去。任何的子应用都是能够访问到这个类的。但是。这中方法的缺点也很明显。首先您失去了在任何特定应用中对指定类进行热部署的能力。第二、这些类发生任何变化意味着server必须从新启动。因为没有一种机制能够让java应用类加载器从新加载这些类。所以当您采用这种方法的时候您要权衡一下得失。

  对您的j2ee应用来说,Log4j是一种扩展类库。那么我们应该把这个类库放到那里去呢。前面提到一种建议是。将他放到weblogic启动时的classpath中。但是前面也讲到了他的缺点。不太建议使用这种方法。但是在j2ee环境下配置log4j会因为ejb无法得知由webapp类加载器加载的classes而有一些自己的特点(ejb和webapp用的类加载器不相同)。除非您的包和应用使用的相同类加载器加载ejb和webapp.下面我为说明这一点举个例子。

  我们会在我们安装的weblogic中部署一个很简单的应用他包括jsp和ejb.这个ejb是个很简单的ejb。当他被调用的时候会返回”hello world”

  Example: Why Doesn’t It Work?

  例子:“他为什么不工作。“

  让我们用weblogic 的控制台安装.war文档和。Ejb的.jar(EJB .jar file)文档。当我们想要安装ejb的.jar文档的时候。我们会发现org.apache.log4j.logger很难找到的错误。

  Ejb的.jar文档无法从和他相对应的webapp的目录下的web-inf目录得到log4j的消息。因为ejb和webapp使用的是不的类加载器.甚至是我们将ejb和webapp打包到同一个ear文档中(.ear file)。我们还是得到错误信息。这是为什么?即使我们将ejb和webapp打包到ear文档中使用相同的类加载器。我们还没有告诉我们的ejb去那里访问log4j.jar文档。

  Example: Why It Will Work

  例子:为什么他工作了。

  这里有个升级后能够工作的ear文档(updated .ear file)让我们看看都做了那些改变。

  • 我将log4j.jar文档从webapp的lib目录下面一移到了外层目录。和.war和ejb.jar文档平级。这

  样使得.jar文档对ejb来讲是可见的。

  •

  我更改的Ejb.jar文档中的Manifest.mf,增加一个条目,使他包含了指向log4j.jar的classpath

  (Class-Path: log4j.jar)

  这些更改已能够使我们将这个应用部署到weblogic上。当我们用控制台部署的时候已没有出错信息了。因为现在ejb能够访问log4j。对于loa4jDemoEar2这个应用只有一个类加载器.它为整个应用加载类库和classes。在EJB中的.mf文件中添加的classpath条目主要用来解决对log4j.jar文件的依赖和加载。Webapp也可以访问到log4j.jar.即使我们将它移到了lib目录的外边。因为他们用的是同一个类加载器。

对于一个j2ee环境采用的策略
    根据你的需求。我建议如下策略。你会发现这不仅仅与log4j相关。而适用于所有需要部署扩展的classes的应用。
    如果你的classes仅仅被你的webapplication使用。那么把它部署到web-info/lib这个目录。
    如果你的web应用和ejb都需要这个classes。那么在你的ejb的.mf文件增加相应的classpath条目。指明需要的classes。并且将classes放到ear文件中的最上一层。和.war、ejb.jar放在同一层次。这样你的ejb和webapp都可以访问这个classes而不需要反复的部署。
结论
    如果你不清出类加载器的工作方式。J2ee的打包工作就会变的非常繁琐。清楚的了解“帽子下面“机制。对成功部署j2ee应用非常重要。它会帮助部署工程师明确自己如何连接这些classes.
      Log4j在j2ee环境下的工作没有什么不同。只是需要能够进行正确的配置。希望这片文章对你有所帮助。

Resources
Tyler Jewell's commentary on EJB 2 and J2EE packaging explains this strategy in more detail.
   IBM has published a document on Websphere-specific classloader issues.  WebLogic's classloader architecture can be accessed here.
   Some information on log4j and classloader issues can be found in the log4j troubleshooting docs.

Vikram Goyal is a serious Java lover with 6+ years of experience.

猜你喜欢

转载自llyzq.iteye.com/blog/1128502