﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-lanxin1020-随笔分类-tools</title><link>http://www.blogjava.net/lanxin1020/category/39379.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 12 May 2009 14:15:17 GMT</lastBuildDate><pubDate>Tue, 12 May 2009 14:15:17 GMT</pubDate><ttl>60</ttl><item><title>ASM(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/05/12/270177.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Tue, 12 May 2009 04:43:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/05/12/270177.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/270177.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/05/12/270177.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/270177.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/270177.html</trackback:ping><description><![CDATA[<p><a><span>什么是 ASM？</span></a></p>
<p>ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件，也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里，这些类文件拥有足够的元数据来解析类中的所有元素：类名称、方法、属性以及 Java 字节码（指令）。ASM 从类文件中读入信息后，能够改变类行为，分析类信息，甚至能够根据用户要求生成新类。</p>
<p>与 BCEL 和 SERL 不同，ASM 提供了更为现代的编程模型。对于 ASM 来说，Java class 被描述为一棵树；使用 &#8220;Visitor&#8221; 模式遍历整个二进制结构；事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分，而不必了解 Java 类文件格式的所有细节：ASM 框架提供了默认的 &#8220;response taker&#8221;处理这一切。</p>
<p><a><span>为什么要动态生成 Java 类？</span></a></p>
<p>动态生成 Java 类与 AOP 密切相关的。AOP 的初衷在于软件设计世界中存在这么一类代码，零散而又耦合：零散是由于一些公有的功能（诸如著名的 log 例子）分散在所有模块之中；同时改变 log 功能又会影响到所有的模块。出现这样的缺陷，很大程度上是由于传统的 面向对象编程注重以继承关系为代表的&#8220;纵向&#8221;关系，而对于拥有相同功能或者说方面 （Aspect）的模块之间的&#8220;横向&#8221;关系不能很好地表达。例如，目前有一个既有的银行管理系统，包括 Bank、Customer、Account、Invoice 等对象，现在要加入一个安全检查模块， 对已有类的所有操作之前都必须进行一次安全检查。</p>
<br />
<a><strong>图 1. ASM &#8211; AOP</strong></a><br />
<img alt="图 1. ASM &#8211; AOP" src="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig001.jpg" /> <br />
<p>然而 Bank、Customer、Account、Invoice 是代表不同的事务，派生自不同的父类，很难在高层上加入关于 Security Checker 的共有功能。对于没有多继承的 Java 来说，更是如此。传统的解决方案是使用 Decorator 模式，它可以在一定程度上改善耦合，而功能仍旧是分散的 —— 每个需要 Security Checker 的类都必须要派生一个 Decorator，每个需要 Security Checker 的方法都要被包装（wrap）。下面我们以 <code>Account</code> 类为例看一下 Decorator：</p>
<p>首先，我们有一个 <code>SecurityChecker</code> 类，其静态方法 <code>checkSecurity</code> 执行安全检查功能：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class SecurityChecker {   public static void checkSecurity() {    System.out.println("SecurityChecker.checkSecurity ...");    //TODO real security check   }   }       </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>另一个是 <code>Account</code> 类：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class Account {   public void operation() {    System.out.println("operation...");    //TODO real operation   }  }       </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>若想对 <code>operation</code> 加入对 <code>SecurityCheck.checkSecurity()</code> 调用，标准的 Decorator 需要先定义一个 <code>Account</code> 类的接口：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public interface Account {   void operation();   }       </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>然后把原来的 <code>Account</code> 类定义为一个实现类：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class AccountImpl extends Account{   public void operation() {    System.out.println("operation...");    //TODO real operation   }  }        </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>定义一个 <code>Account</code> 类的 Decorator，并包装 <code>operation</code> 方法：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class AccountWithSecurityCheck implements Account {    private  Account account;   public AccountWithSecurityCheck (Account account) {    this.account = account;   }   public void operation() {    SecurityChecker.checkSecurity();    account.operation();   }  }       </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在这个简单的例子里，改造一个类的一个方法还好，如果是变动整个模块，Decorator 很快就会演化成另一个噩梦。动态改变 Java 类就是要解决 AOP 的问题，提供一种得到系统支持的可编程的方法，自动化地生成或者增强 Java 代码。这种技术已经广泛应用于最新的 Java 框架内，如 Hibernate，Spring 等。</p>
<p><a><span>为什么选择 ASM？</span></a></p>
<p>最直接的改造 Java 类的方法莫过于直接改写 class 文件。Java 规范详细说明了class 文件的格式，直接编辑字节码确实可以改变 Java 类的行为。直到今天，还有一些 Java 高手们使用最原始的工具，如 UltraEdit 这样的编辑器对 class 文件动手术。是的，这是最直接的方法，但是要求使用者对 Java class 文件的格式了熟于心：小心地推算出想改造的函数相对文件首部的偏移量，同时重新计算 class 文件的校验码以通过 Java 虚拟机的安全机制。</p>
<p>Java 5 中提供的 Instrument 包也可以提供类似的功能：启动时往 Java 虚拟机中挂上一个用户定义的 hook 程序，可以在装入特定类的时候改变特定类的字节码，从而改变该类的行为。但是其缺点也是明显的：</p>
<ul>
    <li>Instrument 包是在整个虚拟机上挂了一个钩子程序，每次装入一个新类的时候，都必须执行一遍这段程序，即使这个类不需要改变。
    <li>直接改变字节码事实上类似于直接改写 class 文件，无论是调用 <code>ClassFileTransformer. transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)</code>，还是 <code>Instrument.redefineClasses(ClassDefinition[] definitions)</code>，都必须提供新 Java 类的字节码。也就是说，同直接改写 class 文件一样，使用 Instrument 也必须了解想改造的方法相对类首部的偏移量，才能在适当的位置上插入新的代码。 </li>
</ul>
<p>尽管 Instrument 可以改造类，但事实上，Instrument 更适用于监控和控制虚拟机的行为。</p>
<p>一种比较理想且流行的方法是使用 <code>java.lang.ref.proxy</code>。我们仍旧使用上面的例子，给 <code>Account</code> 类加上 checkSecurity 功能:</p>
<p>首先，Proxy 编程是面向接口的。下面我们会看到，Proxy 并不负责实例化对象，和 Decorator 模式一样，要把 <code>Account</code> 定义成一个接口，然后在 <code>AccountImpl</code> 里实现 <code>Account</code> 接口，接着实现一个 <code>InvocationHandler</code> <code>Account</code> 方法被调用的时候，虚拟机都会实际调用这个 <code>InvocationHandler</code> 的 <code>invoke</code> 方法：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>class SecurityProxyInvocationHandler implements InvocationHandler {   private Object proxyedObject;   public SecurityProxyInvocationHandler(Object o) {    proxyedObject = o;   }       public Object invoke(Object object, Method method, Object[] arguments)    throws Throwable {       if (object instanceof Account &amp;&amp; method.getName().equals("opertaion")) {     SecurityChecker.checkSecurity();    }    return method.invoke(proxyedObject, arguments);   }  }    </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>最后，在应用程序中指定 <code>InvocationHandler</code> 生成代理对象：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public static void main(String[] args) {   Account account = (Account) Proxy.newProxyInstance(    Account.class.getClassLoader(),    new Class[] { Account.class },    new SecurityProxyInvocationHandler(new AccountImpl())   );   account.function();  }   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>其不足之处在于：</p>
<ul>
    <li>Proxy 是面向接口的，所有使用 Proxy 的对象都必须定义一个接口，而且用这些对象的代码也必须是对接口编程的：Proxy 生成的对象是接口一致的而不是对象一致的：例子中 <code>Proxy.newProxyInstance</code> 生成的是实现 <code>Account</code> 接口的对象而不是 <code>AccountImpl</code> 的子类。这对于软件架构设计，尤其对于既有软件系统是有一定掣肘的。
    <li>Proxy 毕竟是通过反射实现的，必须在效率上付出代价：有实验数据表明，调用反射比一般的函数开销至少要大 10 倍。而且，从程序实现上可以看出，对 proxy class 的所有方法调用都要通过使用反射的 invoke 方法。因此，对于性能关键的应用，使用 proxy class 是需要精心考虑的，以避免反射成为整个应用的瓶颈。 </li>
</ul>
<p>ASM 能够通过改造既有类，直接生成需要的代码。增强的代码是硬编码在新生成的类文件内部的，没有反射带来性能上的付出。同时，ASM 与 Proxy 编程不同，不需要为增强代码而新定义一个接口，生成的代码可以覆盖原来的类，或者是原始类的子类。它是一个普通的 Java 类而不是 proxy 类，甚至可以在应用程序的类框架中拥有自己的位置，派生自己的子类。</p>
<p>相比于其他流行的 Java 字节码操纵工具，ASM 更小更快。ASM 具有类似于 BCEL 或者 SERP 的功能，而只有 33k 大小，而后者分别有 350k 和 150k。同时，同样类转换的负载，如果 ASM 是 60% 的话，BCEL 需要 700%，而 SERP 需要 1100% 或者更多。</p>
<p>ASM 已经被广泛应用于一系列 Java 项目：AspectWerkz、AspectJ、BEA WebLogic、IBM AUS、OracleBerkleyDB、Oracle TopLink、Terracotta、RIFE、EclipseME、Proactive、Speedo、Fractal、EasyBeans、BeanShell、Groovy、Jamaica、CGLIB、dynaop、Cobertura、JDBCPersistence、JiP、SonarJ、Substance L&amp;F、Retrotranslator 等。Hibernate 和 Spring 也通过 cglib，另一个更高层一些的自动代码生成工具使用了 ASM。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
            <img border="0" alt="" src="http://www.ibm.com/i/c.gif" width="8" height="6" /></td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="4" /><br />
            <table border="0" cellspacing="0" cellpadding="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img border="0" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" height="16" /><br />
                        </td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a><span>Java 类文件概述</span></a></p>
<p>所谓 Java 类文件，就是通常用 javac 编译器产生的 .class 文件。这些文件具有严格定义的格式。为了更好的理解 ASM，首先对 Java 类文件格式作一点简单的介绍。Java 源文件经过 javac 编译器编译之后，将会生成对应的二进制文件（如下图所示）。每个合法的 Java 类文件都具备精确的定义，而正是这种精确的定义，才使得 Java 虚拟机得以正确读取和解释所有的 Java 类文件。</p>
<br />
<a><strong>图 2. ASM &#8211; Javac 流程</strong></a><br />
<img alt="图 2. ASM &#8211; Javac 流程" src="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig002.jpg" /> <br />
<p>Java 类文件是 8 位字节的二进制流。数据项按顺序存储在 class 文件中，相邻的项之间没有间隔，这使得 class 文件变得紧凑，减少存储空间。在 Java 类文件中包含了许多大小不同的项，由于每一项的结构都有严格规定，这使得 class 文件能够从头到尾被顺利地解析。下面让我们来看一下 Java 类文件的内部结构，以便对此有个大致的认识。</p>
<p>例如，一个最简单的 Hello World 程序：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class HelloWorld {   public static void main(String[] args) {    System.out.println("Hello world");   }  }  </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>经过 javac 编译后，得到的类文件大致是：</p>
<br />
<a><strong>图 3. ASM &#8211; Java 类文件</strong></a><br />
<img alt="图 3. ASM &#8211; Java 类文件" src="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig003.jpg" /> <br />
<p>从上图中可以看到，一个 Java 类文件大致可以归为 10 个项：</p>
<ul>
    <li><strong>Magic：</strong>该项存放了一个 Java 类文件的魔数（magic number）和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的，这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。
    <li><strong>Version：</strong>该项存放了 Java 类文件的版本信息，它对于一个 Java 文件具有重要的意义。因为 Java 技术一直在发展，所以类文件的格式也处在不断变化之中。类文件的版本信息让虚拟机知道如何去读取并处理该类文件。
    <li><strong>Constant Pool：</strong>该项存放了类中各种文字字符串、类名、方法名和接口名称、final 变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池，常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用，因此它在 Java 的动态链接中起到了核心的作用。常量池的大小平均占到了整个类大小的 60% 左右。
    <li><strong>Access_flag：</strong>该项指明了该文件中定义的是类还是接口（一个 class 文件中只能有一个类或接口），同时还指名了类或接口的访问标志，如 public，private, abstract 等信息。
    <li><strong>This Class：</strong>指向表示该类全限定名称的字符串常量的指针。
    <li><strong>Super Class：</strong>指向表示父类全限定名称的字符串常量的指针。
    <li><strong>Interfaces：</strong>一个指针数组，存放了该类或父类实现的所有接口名称的字符串常量的指针。以上三项所指向的常量，特别是前两项，在我们用 ASM 从已有类派生新类时一般需要修改：将类名称改为子类名称；将父类改为派生前的类名称；如果有必要，增加新的实现接口。
    <li><strong>Fields：</strong>该项对类或接口中声明的字段进行了细致的描述。需要注意的是，fields 列表中仅列出了本类或接口中的字段，并不包括从超类和父接口继承而来的字段。
    <li><strong>Methods：</strong>该项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是，methods 列表里仅存放了本类或本接口中的方法，并不包括从超类和父接口继承而来的方法。使用 ASM 进行 AOP 编程，通常是通过调整 Method 中的指令来实现的。
    <li><strong>Class attributes：</strong>该项存放了在该文件中类或接口所定义的属性的基本信息。 </li>
</ul>
<p>事实上，使用 ASM 动态生成类，不需要像早年的 class hacker 一样，熟知 class 文件的每一段，以及它们的功能、长度、偏移量以及编码方式。ASM 会给我们照顾好这一切的，我们只要告诉 ASM 要改动什么就可以了 —— 当然，我们首先得知道要改什么：对类文件格式了解的越多，我们就能更好地使用 ASM 这个利器。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
            <img border="0" alt="" src="http://www.ibm.com/i/c.gif" width="8" height="6" /></td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="4" /><br />
            <table border="0" cellspacing="0" cellpadding="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img border="0" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" height="16" /><br />
                        </td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a><span>ASM 3.0 编程框架</span></a></p>
<p>ASM 通过树这种数据结构来表示复杂的字节码结构，并利用 Push 模型来对树进行遍历，在遍历过程中对字节码进行修改。所谓的 Push 模型类似于简单的 Visitor 设计模式，因为需要处理字节码结构是固定的，所以不需要专门抽象出一种 Vistable 接口，而只需要提供 Visitor 接口。所谓 Visitor 模式和 Iterator 模式有点类似，它们都被用来遍历一些复杂的数据结构。Visitor 相当于用户派出的代表，深入到算法内部，由算法安排访问行程。Visitor 代表可以更换，但对算法流程无法干涉，因此是被动的，这也是它和 Iterator 模式由用户主动调遣算法方式的最大的区别。</p>
<p>在 ASM 中，提供了一个 <code>ClassReader</code> 类，这个类可以直接由字节数组或由 class 文件间接的获得字节码数据，它能正确的分析字节码，构建出抽象的树在内存中表示字节码。它会调用 <code>accept</code> 方法，这个方法接受一个实现了 <code>ClassVisitor</code> 接口的对象实例作为参数，然后依次调用 <code>ClassVisitor</code> 接口的各个方法。字节码空间上的偏移被转换成 visit 事件时间上调用的先后，所谓 visit 事件是指对各种不同 visit 函数的调用，<code>ClassReader</code> 知道如何调用各种 visit 函数。在这个过程中用户无法对操作进行干涉，所以遍历的算法是确定的，用户可以做的是提供不同的 Visitor 来对字节码树进行不同的修改。<code>ClassVisitor</code> 会产生一些子过程，比如 <code>visitMethod</code> 会返回一个实现 <code>MethordVisitor</code> 接口的实例，<code>visitField</code> 会返回一个实现 <code>FieldVisitor</code> 接口的实例，完成子过程后控制返回到父过程，继续访问下一节点。因此对于 <code>ClassReader</code> 来说，其内部顺序访问是有一定要求的。实际上用户还可以不通过 <code>ClassReader</code> 类，自行手工控制这个流程，只要按照一定的顺序，各个 visit 事件被先后正确的调用，最后就能生成可以被正确加载的字节码。当然获得更大灵活性的同时也加大了调整字节码的复杂度。</p>
<p>各个 <code>ClassVisitor</code> 通过职责链 （Chain-of-responsibility） 模式，可以非常简单的封装对字节码的各种修改，而无须关注字节码的字节偏移，因为这些实现细节对于用户都被隐藏了，用户要做的只是覆写相应的 visit 函数。</p>
<p><code>ClassAdaptor</code> 类实现了 <code>ClassVisitor</code> 接口所定义的所有函数，当新建一个 <code>ClassAdaptor</code> 对象的时候，需要传入一个实现了 <code>ClassVisitor</code> 接口的对象，作为职责链中的下一个访问者 （Visitor），这些函数的默认实现就是简单的把调用委派给这个对象，然后依次传递下去形成职责链。当用户需要对字节码进行调整时，只需从 <code>ClassAdaptor</code> 类派生出一个子类，覆写需要修改的方法，完成相应功能后再把调用传递下去。这样，用户无需考虑字节偏移，就可以很方便的控制字节码。</p>
<p>每个 <code>ClassAdaptor</code> 类的派生类可以仅封装单一功能，比如删除某函数、修改字段可见性等等，然后再加入到职责链中，这样耦合更小，重用的概率也更大，但代价是产生很多小对象，而且职责链的层次太长的话也会加大系统调用的开销，用户需要在低耦合和高效率之间作出权衡。用户可以通过控制职责链中 visit 事件的过程，对类文件进行如下操作：</p>
<ol>
    <li>
    <p>删除类的字段、方法、指令：只需在职责链传递过程中中断委派，不访问相应的 visit 方法即可，比如删除方法时只需直接返回 <code>null</code>，而不是返回由 <code>visitMethod</code> 方法返回的 <code>MethodVisitor</code> 对象。</p>
    <table border="0" cellspacing="0" cellpadding="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>class DelLoginClassAdapter extends ClassAdapter {   public DelLoginClassAdapter(ClassVisitor cv) {    super(cv);   }     public MethodVisitor visitMethod(final int access, final String name,    final String desc, final String signature, final String[] exceptions) {    if (name.equals("login")) {     return null;    }    return cv.visitMethod(access, name, desc, signature, exceptions);   }  }           </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <li>
    <p>修改类、字段、方法的名字或修饰符：在职责链传递过程中替换调用参数。</p>
    <table border="0" cellspacing="0" cellpadding="0" width="100%">
        <tbody>
            <tr>
                <td>
                <pre>class AccessClassAdapter extends ClassAdapter {   public AccessClassAdapter(ClassVisitor cv) {    super(cv);   }     public FieldVisitor visitField(final int access, final String name,          final String desc, final String signature, final Object value) {          int privateAccess = Opcodes.ACC_PRIVATE;          return cv.visitField(privateAccess, name, desc, signature, value);      }  }           </pre>
                </td>
            </tr>
        </tbody>
    </table>
    <br />
    <li>
    <p>增加新的类、方法、字段</p>
    </li>
</ol>
<p>ASM 的最终的目的是生成可以被正常装载的 class 文件，因此其框架结构为客户提供了一个生成字节码的工具类 —— <code>ClassWriter</code>。它实现了 <code>ClassVisitor</code> 接口，而且含有一个 <code>toByteArray()</code> 函数，返回生成的字节码的字节流，将字节流写回文件即可生产调整后的 class 文件。一般它都作为职责链的终点，把所有 visit 事件的先后调用（时间上的先后），最终转换成字节码的位置的调整（空间上的前后），如下例：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>ClassWriter  classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);  ClassAdaptor delLoginClassAdaptor = new DelLoginClassAdapter(classWriter);  ClassAdaptor accessClassAdaptor = new AccessClassAdaptor(delLoginClassAdaptor);     ClassReader classReader = new ClassReader(strFileName);  classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);           </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>综上所述，ASM 的时序图如下：</p>
<br />
<a><strong>图 4. ASM &#8211; 时序图</strong></a><br />
<img alt="图 4. ASM &#8211; 时序图" src="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/fig004.jpg" /> <br />
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
            <img border="0" alt="" src="http://www.ibm.com/i/c.gif" width="8" height="6" /></td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="4" /><br />
            <table border="0" cellspacing="0" cellpadding="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img border="0" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" height="16" /><br />
                        </td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a><span>使用 ASM3.0 进行 AOP 编程</span></a></p>
<p>我们还是用上面的例子，给 <code>Account</code> 类加上 security check 的功能。与 proxy 编程不同，ASM 不需要将 <code>Account</code> 声明成接口，<code>Account</code> 可以仍旧是一个实现类。ASM 将直接在 <code>Account</code> 类上动手术，给 <code>Account</code> 类的 <code>operation</code> 方法首部加上对 <code>SecurityChecker.checkSecurity</code> 的调用。</p>
<p>首先，我们将从 <code>ClassAdapter</code> 继承一个类。<code>ClassAdapter</code> 是 ASM 框架提供的一个默认类，负责沟通 <code>ClassReader</code> 和 <code>ClassWriter</code>。如果想要改变 <code>ClassReader</code> 处读入的类，然后从 <code>ClassWriter</code> 处输出，可以重写相应的 <code>ClassAdapter</code> 函数。这里，为了改变 <code>Account</code> 类的 <code>operation</code> 方法，我们将重写 <code>visitMethdod</code> 方法。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>class AddSecurityCheckClassAdapter extends ClassAdapter{     public AddSecurityCheckClassAdapter(ClassVisitor cv) {    //Responsechain 的下一个 ClassVisitor，这里我们将传入 ClassWriter，    //负责改写后代码的输出    super(cv);   }      //重写 visitMethod，访问到 "operation" 方法时，   //给出自定义 MethodVisitor，实际改写方法内容   public MethodVisitor visitMethod(final int access, final String name,    final String desc, final String signature, final String[] exceptions) {    MethodVisitor mv = cv.visitMethod(access, name, desc, signature,exceptions);    MethodVisitor wrappedMv = mv;    if (mv != null) {     //对于 "operation" 方法     if (name.equals("operation")) {       //使用自定义 MethodVisitor，实际改写方法内容      wrappedMv = new AddSecurityCheckMethodAdapter(mv);      }     }    return wrappedMv;   }  }　　　  </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>下一步就是定义一个继承自 <code>MethodAdapter</code> 的 <code>AddSecurityCheckMethodAdapter</code>，在&#8220;<code>operation</code>&#8221;方法首部插入对 <code>SecurityChecker.checkSecurity()</code> 的调用。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>class AddSecurityCheckMethodAdapter extends MethodAdapter {   public AddSecurityCheckMethodAdapter(MethodVisitor mv) {    super(mv);   }     public void visitCode() {    visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker",     "checkSecurity", "()V");   }  }      </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>其中，<code>ClassReader</code> 读到每个方法的首部时调用 <code>visitCode()</code>，在这个重写方法里，我们用<code>visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker","checkSecurity", "()V");</code> 插入了安全检查功能。</p>
<p>最后，我们将集成上面定义的 <code>ClassAdapter</code>，<code>ClassReader</code>和<code>ClassWriter</code> 产生修改后的 <code>Account</code> 类文件:</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>import java.io.File;  import java.io.FileOutputStream;  import org.objectweb.asm.*;        public class Generator{   public static void main() throws Exception {    ClassReader cr = new ClassReader("Account");    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);    ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);    cr.accept(classAdapter, ClassReader.SKIP_DEBUG);    byte[] data = cw.toByteArray();    File file = new File("Account.class");    FileOutputStream fout = new FileOutputStream(file);    fout.write(data);    fout.close();   }  }   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>执行完这段程序后，我们会得到一个新的 Account.class 文件，如果我们使用下面代码：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class Main {   public static void main(String[] args) {    Account account = new Account();    account.operation();   }  }   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>使用这个 Account，我们会得到下面的输出：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>SecurityChecker.checkSecurity ...  operation...   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>也就是说，在 <code>Account</code> 原来的 <code>operation</code> 内容执行之前，进行了 <code>SecurityChecker.checkSecurity()</code> 检查。</p>
<p><a><span>将动态生成类改造成原始类 Account 的子类</span></a></p>
<p>上面给出的例子是直接改造 <code>Account</code> 类本身的，从此 <code>Account</code> 类的 <code>operation</code> 方法必须进行 checkSecurity 检查。但事实上，我们有时仍希望保留原来的 <code>Account</code> 类，因此把生成类定义为原始类的子类是更符合 AOP 原则的做法。下面介绍如何将改造后的类定义为 <code>Account</code> 的子类 <code>Account$EnhancedByASM</code>。其中主要有两项工作:</p>
<ul>
    <li>改变 Class Description, 将其命名为 <code>Account$EnhancedByASM</code>，将其父类指定为 <code>Account</code>。
    <li>改变构造函数，将其中对父类构造函数的调用转换为对 <code>Account</code> 构造函数的调用。 </li>
</ul>
<p>在 <code>AddSecurityCheckClassAdapter</code> 类中，将重写 <code>visit</code> 方法：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public void visit(final int version, final int access, final String name,    final String signature, final String superName,    final String[] interfaces) {   String enhancedName = name + "$EnhancedByASM";  //改变类命名   enhancedSuperName = name; //改变父类，这里是&#8221;Account&#8221;   super.visit(version, access, enhancedName, signature,   enhancedSuperName, interfaces);  }   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>改进 <code>visitMethod</code> 方法，增加对构造函数的处理：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public MethodVisitor visitMethod(final int access, final String name,   final String desc, final String signature, final String[] exceptions) {   MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);   MethodVisitor wrappedMv = mv;   if (mv != null) {    if (name.equals("operation")) {     wrappedMv = new AddSecurityCheckMethodAdapter(mv);    } else if (name.equals("&lt;init&gt;")) {     wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,      enhancedSuperName);    }   }   return wrappedMv;  }   </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这里 <code>ChangeToChildConstructorMethodAdapter</code> 将负责把 <code>Account</code> 的构造函数改造成其子类 <code>Account$EnhancedByASM</code> 的构造函数：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>class ChangeToChildConstructorMethodAdapter extends MethodAdapter {   private String superClassName;     public ChangeToChildConstructorMethodAdapter(MethodVisitor mv,    String superClassName) {    super(mv);    this.superClassName = superClassName;   }     public void visitMethodInsn(int opcode, String owner, String name,    String desc) {    //调用父类的构造函数时    if (opcode == Opcodes.INVOKESPECIAL &amp;&amp; name.equals("&lt;init&gt;")) {      owner = superClassName;    }    super.visitMethodInsn(opcode, owner, name, desc);//改写父类为superClassName   }  }  </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>最后演示一下如何在运行时产生并装入产生的 <code>Account$EnhancedByASM</code>。 我们定义一个 <code>Util</code> 类，作为一个类工厂负责产生有安全检查的 <code>Account</code> 类：</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre>public class SecureAccountGenerator {     private static AccountGeneratorClassLoader classLoader =     new AccountGeneratorClassLoade();   private static Class secureAccountClass;     public Account generateSecureAccount() throws ClassFormatError,     InstantiationException, IllegalAccessException {    if (null == secureAccountClass) {                 ClassReader cr = new ClassReader("Account");     ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);     ClassAdapter classAdapter = new AddSecurityCheckClassAdapter(cw);     cr.accept(classAdapter, ClassReader.SKIP_DEBUG);     byte[] data = cw.toByteArray();     secureAccountClass = classLoader.defineClassFromClassFile(      "Account$EnhancedByASM",data);    }    return (Account) secureAccountClass.newInstance();   }     private static class AccountGeneratorClassLoader extends ClassLoader {    public Class defineClassFromClassFile(String className,     byte[] classFile) throws ClassFormatError {     return defineClass("Account$EnhancedByASM", classFile, 0, classFile.length());    }   }  }  </pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>静态方法 <code>SecureAccountGenerator.generateSecureAccount()</code> 在运行时动态生成一个加上了安全检查的 <code>Account</code> 子类。著名的 Hibernate 和 Spring 框架，就是使用这种技术实现了 AOP 的&#8220;无损注入&#8221;。</p>
<br />
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" height="1" /><br />
            <img border="0" alt="" src="http://www.ibm.com/i/c.gif" width="8" height="6" /></td>
        </tr>
    </tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
    <tbody>
        <tr align="right">
            <td><img alt="" src="http://www.ibm.com/i/c.gif" width="100%" height="4" /><br />
            <table border="0" cellspacing="0" cellpadding="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img border="0" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" height="16" /><br />
                        </td>
                        <td valign="top" align="right"><a href="http://www.ibm.com/developerworks/cn/java/j-lo-asm30/index.html#main"><strong>回页首</strong></a></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><a><span>小结</span></a></p>
<p>最后，我们比较一下 ASM 和其他实现 AOP 的底层技术：</p>
<img src ="http://www.blogjava.net/lanxin1020/aggbug/270177.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-12 12:43 <a href="http://www.blogjava.net/lanxin1020/archive/2009/05/12/270177.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j（转）</title><link>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268850.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Mon, 04 May 2009 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268850.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/268850.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/268850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/268850.html</trackback:ping><description><![CDATA[<div class="postbody clearfix">
<div style="position: relative" id="related_topics" _madepositioned="true">Log4J是Apache的一个开放源代码项目(<a href="http://logging.apache.org/log4j/docs/"><font color="#73af1d">http://logging.apache.org/log4j/docs/</font></a>)，它是一个日志操作包。通过使用Log4J,可以指定日志信息输出的目的地，控制每一条日志的输出格式，定义日志信息的级别。所有这些功能通过一个配置文件灵活进行配置。 </div>
<p>一、LOG4J组成</p>
<p>&nbsp;&nbsp;&nbsp; LOG4J主要由三大组件组成：<br />
&nbsp;&nbsp;&nbsp; . Logger: 决定什么日志信息应该被输出、什么日志信息应该被忽略；<br />
&nbsp;&nbsp;&nbsp; . Appender: 指定日志信息应该输出到什么地方, 这些地方可以是控制台、文件、网络设备；<br />
&nbsp;&nbsp;&nbsp; . Layout: 指定日志信息的输出格式；</p>
<p>&nbsp;&nbsp;&nbsp; 一个Logger可以有多个Appender，也就是说日志信息可以同时输出到多个设备上，每个Appender对应<br />
&nbsp;&nbsp;&nbsp; 一种Layout(示例见下图)。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ↗&nbsp; Appender1&nbsp; &#8594;&nbsp; Layout<br />
&nbsp;&nbsp;&nbsp;&nbsp; ／&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; Logger<br />
&nbsp;&nbsp;&nbsp;&nbsp; ﹨ &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ↘&nbsp; Appender2&nbsp; &#8594;&nbsp; Layout</p>
<p><br />
二、Logger组件</p>
<p>&nbsp;&nbsp;&nbsp; 1. Logger组件提供的方法：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger组件是LOG4J的核心组件，它代表了Log4J的日志记录器，它能够对日志信息进行分类筛选。它由org.apache.log4j.Logger类实现，提供了如下方法：</p>
<p>&nbsp;</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">package</span><span>&nbsp;org.apache.log4j; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li class="alt"><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Logger&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Creation&nbsp;&amp;&nbsp;retrieval&nbsp;methods: </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Logger&nbsp;getRootLogger(); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;Logger&nbsp;getLogger(String&nbsp;name); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;printing&nbsp;methods: </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;debug(Object&nbsp;message); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;info(Object&nbsp;message); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;warn(Object&nbsp;message); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;error(Object&nbsp;message); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;fatal(Object&nbsp;message); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;generic&nbsp;printing&nbsp;method: </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;log(Priority&nbsp;p,&nbsp;Object&nbsp;message); &nbsp;&nbsp;</span>
    <li><span>} &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp; 2. 在配置文件中配置Logger组件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可在Log4J配置文件中配置自己的Logger组件，示例：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.logger.myLogger=WARN</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上代码定义了一个Logger组件，名称为myLogger，日志级别为WARN。<br />
&nbsp; <br />
&nbsp;&nbsp;&nbsp; 3. 日志级别种类：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一共有五种，级别由高到低依次是：fatal、error、warn、info、debug。获得Logger实例后，我们可调用以下方法之一输出日志信息：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void debug(Object message);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出debug级别的日志信息；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void info(Object message);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出info级别的日志信息；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void warn(Object message);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出warn级别的日志信息；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void error(Object message);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出error级别的日志信息；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void fatal(Object message);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //输出fatal级别的日志信息；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void log(Priority p, Object message);//输出参数Priority指定级别的日志信息；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上方法只有当它的级别大于或等于Logger组件配置的日志级别时才调用。以前面我们配置的myLogger为例，它的日志级别为WARN, 那么在程序中，它的warn()、error()、fatal()方法会被执行。对于log()方法，只有当它的参数Priority指定的日志级别大于或等于WARN时，它才会被执行。</p>
<p>&nbsp;&nbsp;&nbsp; 4. 为什么需要对日志进行分级？<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在写程序的时候，为了调试程序，我们会在很多出错的地方输出大量的日志信息。当程序调试完，不需要这些信息时，将程序中这些输出日志信息代码删除吗？这样费时费力，对于大型程序几乎不可行。通过对日志分级，假如不想输出WARN级别的日志信息，则Logger组件的级别调高即可，省时省心。</p>
<p>&nbsp;&nbsp;&nbsp; 5. Logger组件的继承性</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log4J提供了一个root Logger，它是所有Logger组件的&#8220;祖先&#8221;,它永远存在，且不能通过名字检索或引用，通过Logger.getRootLogger()方法取得它。配置root Logger代码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.rootLogger=INFO,console</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可在配置文件中方便地配置存在继承关系的Logger组件，凡是在符号&#8220;.&#8221;后面的组件都会成为在符号&#8220;.&#8221;前面的Logger组件的子类。例如：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.apache.myLogger=WARN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.apache.myLogger.mySonLogger=,file</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上代码中, mySonLogger是myLogger的子类Logger组件。Logger组件的继承关系：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 如果子类Logger组件没有定义日志级别，则将继承父类的日志级别;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 如果子类Logger组件定义了日志级别，就不会继承父类的日志级别;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 黙认情况下，子类Logger组件会继承父类所有的Appender，把它们加入到自己的Appener;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 如果把子类Logger组件的additivity标志设为false，那么它就不会继承父类Appender。additivity标志&nbsp;默认值为false；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上配置的三个Logger继承关系示例如图：<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root Logger: 日志级别=INFO&nbsp; appender清单=console<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8593;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger: 日志级别=WARN appender清单=null<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8593;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger: 日志级别=null appender清单=file </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这三个Logger组件实际日志级别和Appender如下表：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger组件&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志级别&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Appender清单<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root Logger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INFO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; console(继承)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN(继承)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; file，console(继承)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
三、Appender组件</p>
<p>&nbsp;&nbsp;&nbsp; Appender组件决定将日志信息输出到什么地方。支持以下目的地：<br />
&nbsp;&nbsp;&nbsp; . 控制台(Console);<br />
&nbsp;&nbsp;&nbsp; . 文件(File);<br />
&nbsp;&nbsp;&nbsp; . GUI组件(GUI component);<br />
&nbsp;&nbsp;&nbsp; . 套接口服务器(Remote socket server);<br />
&nbsp;&nbsp;&nbsp; . NT的事件记录器(NT Event Logger);<br />
&nbsp;&nbsp;&nbsp; . UNIX Syslog守护进程(Remote UNIX Syslog daemon);</p>
<p>&nbsp;&nbsp;&nbsp; 一个Logger可同时对应多个Appender，示例：myLogger配置二个Appender: 一个file, 一个是console：</p>
<p>&nbsp;&nbsp;&nbsp; log4j.logger.myAppender=WARN,file,console</p>
<p>&nbsp;&nbsp;&nbsp; log4j.appender.file=org.apache.log4j.RollingFileAppender<br />
&nbsp;&nbsp;&nbsp; log4j.appender.file.File=log.txt</p>
<p>&nbsp;&nbsp;&nbsp; log4j.apender.console=org.apache.log4j.ConsoleAppender</p>
<p>四、Layout组件</p>
<p>&nbsp;&nbsp;&nbsp; Layout组件决定日志输出格式，有以下几种类型：<br />
&nbsp;&nbsp;&nbsp; . org.apache.log4j.HTMLLayout(以HTML表格形式布局);<br />
&nbsp;&nbsp;&nbsp; . org.apache.log4j.PatternLayout(可以灵活地指定布局模式);<br />
&nbsp;&nbsp;&nbsp; . org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串);<br />
&nbsp;&nbsp;&nbsp; . org.apache.log4j.TTCCLayout(包含日志产生的时间、线程和类别等信息);<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 为名称为console的Appender配置SimpleLayout，代码如下：</p>
<p>&nbsp;&nbsp;&nbsp; log4j.appender.console.layout=org.apache.log4j.SimpleLayout</p>
<p>&nbsp;&nbsp;&nbsp; 输出日志格式如下：</p>
<p>&nbsp;&nbsp;&nbsp; WARN - This is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 为名称为file的Appender配置PatternLayout，代码如下：</p>
<p>&nbsp;&nbsp;&nbsp; log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />
&nbsp;&nbsp;&nbsp; log4j.appender.file.layout.ConversionPattern=%t %p - %m%n</p>
<p>&nbsp;&nbsp;&nbsp; 输出日志格式如下：</p>
<p>&nbsp;&nbsp;&nbsp; THREAD-1 WARN - This is a log message from the myLogger</p>
<p>&nbsp;&nbsp;&nbsp; PatternLayout让开发者依照ConversionPattern定义输出格式。ConversionPattern中一些指定日志内容和格式的预定义符号说明如下：</p>
<p>&nbsp;&nbsp;&nbsp; 符号&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述<br />
&nbsp;&nbsp;&nbsp; %r&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自程序开始后消耗的毫秒数<br />
&nbsp;&nbsp;&nbsp; %t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示日志记录请求生成的线程<br />
&nbsp;&nbsp;&nbsp; %p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示日专语句的优先级<br />
&nbsp;&nbsp;&nbsp; %r&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 与日志请求相关的类别名称<br />
&nbsp;&nbsp;&nbsp; %c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志信息所在的类名<br />
&nbsp;&nbsp;&nbsp; %m%n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 表示日志信息的内容</p>
<p>五、Log4J的基本用法</p>
<p>&nbsp;&nbsp;&nbsp; 1. 定义配置文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log4J支持二种配置文件格式：XML和Java属性文件(采用&#8220;键=值&#8221;形式)。以下为Java属性文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 格式配置文件：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 配置Logger组件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置root Logger语法为：log4j.rootLogger=[priority],appenderName,appenderName,...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置自定义Logger组件语法为：log4j.logger.loggerName=[priority],appenderName,appenderName,...</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中：priority为日志级别，可选值包括FATAL、ERROR、WARN、INFO、DEBUG、ALL；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; appenderName指定Appender组件，可指定多个;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 配置Appender组件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置日志信息输出目的地Appender, 语法为：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName=fully.ualified.name.of.appender.class<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName.option1=value1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName.optionN=valueN</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Log4J提供的Appender有以下几种：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a. org.apache.log4j.ConsoleAppender(控制台);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b. org.apache.log4j.FileAppender(文件);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c. org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d. org.apache.log4j.RollingFileAppender(文件大小到指定尺寸产生一个新的文件);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e. org.apache.log4j.WriteAppender(将日志信息以流格式发送到任意指定地方);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 配置Layout组件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 配置Layout组件语法为：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName.layout=fully.ualified.name.of.appender.class<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName.layout.option1=value1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.appenderName.layout.optionN=valueN</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面为一配置文件示例，文件名为log4j.properties：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ## LOGGERS ##</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #configure root logger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.rootLogger=INFO,console<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #define a logger named myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.logger.myLogger=WARN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #define a second logger that is a child to myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.logger.myLogger.mySonLogger=,file</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ## APPENDERS ##</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #define an appender named console, which is set to be a ConsoleAppender<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.console=org.apache.log4j.ConsoleAppender</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # define an appender named file, which is set to be a RollingFileAppender<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.file=org.apache.log4j.FileAppender<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.file.File=log.txt</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ## LAYOUTS ##<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # assian a SimpleLayout to console appender<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.console.layout=org.apache.log4j.SimpleLayout</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # assian a PatternLayout to file appender<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.file.layout.ConversionPattern=%t%p-%m%n<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 2. 程序中使用Log4j</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 获得日志记录器：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 获得rootLogger：Logger rootLogger=Logger.getRootLogger();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 获得自定义Logger：Logger myLogger = Logger.getLogger("log4j.logger.myLogger");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 读取日志记录器，配置Log4J环境;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a. BasicConfigurator.configure(): 自动快速地使用默认Log4J环境;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b. Property.configurator.configure(String configFilename): 读取使用Java属性格式的配置文件并配置Log4J环境；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c. DOMConfigurator.configure(String filename): 读取XML形式的配置文件并配置LOG4J环境;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; . 输出日志信息;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在程序代码中需要生成日志的地方，调用Logger的各种输出日志方法输出不同级别的日志，例如：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.debug("Thie is a log message from the " + myLogger.getName());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面为一使用Log4J的程序，程序名为Test.java：</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">
<ol class="dp-j">
    <li class="alt"><span><span>&nbsp;</span><span class="keyword">import</span><span>&nbsp;org.apache.log4j.Logger; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;</span><span class="keyword">import</span><span>&nbsp;org.apache.log4j.PropertyConfigurator; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Test&nbsp;{ &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//Get&nbsp;an&nbsp;instance&nbsp;of&nbsp;the&nbsp;myLogger </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger&nbsp;myLogger&nbsp;=&nbsp;Logger.getLogger(</span><span class="string">"myLogger"</span><span>); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//Get&nbsp;an&nbsp;instance&nbsp;of&nbsp;the&nbsp;childLogger </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Logger&nbsp;mySonLogger&nbsp;=&nbsp;Logger.getLogger(</span><span class="string">"myLogger.mySonLogger"</span><span>); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//Load&nbsp;the&nbsp;proerties&nbsp;using&nbsp;the&nbsp;PropertyConfigurator </span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(</span><span class="string">"log4j.properties"</span><span>); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//Log&nbsp;Messages&nbsp;using&nbsp;the&nbsp;Parent&nbsp;Logger </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLogger.debug(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;myLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLogger.info(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;myLogger.getName()); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLogger.warn(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;&nbsp;myLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLogger.error(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;myLogger.getName()); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myLogger.fatal(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;myLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySonLogger.debug(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;mySonLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySonLogger.info(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;mySonLogger.getName()); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySonLogger.warn(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;&nbsp;mySonLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySonLogger.error(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;mySonLogger.getName()); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mySonLogger.fatal(</span><span class="string">"Thie&nbsp;is&nbsp;a&nbsp;log&nbsp;message&nbsp;from&nbsp;the&nbsp;"</span><span>&nbsp;+&nbsp;mySonLogger.getName()); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>} &nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 程序运行结果为:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另在Test.class所在的目录下看到一个log.txt文件，内容如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如将配置文件log4j.properties中语句</p>
<p>&nbsp;log4j.logger.myLogger.mySonLogger=,file</p>
<p>&nbsp;改为</p>
<p>&nbsp;log4j.logger.myLogger.mySonLogger=,file,console</p>
<p>&nbsp;再次运行程序，结果如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger的日志在控制台上输出了二次，这是因为mySonLogger继承了父类console Appender，<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 本身又定义了一个console Appender, 因而有二个console Appender。</p>
<p>六、在web应用中使用Log4J</p>
<p>&nbsp;&nbsp;&nbsp; 创建一个Servlet，在它初始化方法中读取Log4J配置文件并配置Log4J环境，这个Servlet在Web应用启<br />
&nbsp;&nbsp;&nbsp; 动时候被加载和初始化，然后就可在其它Web组件中获取Logger对象并输出日志。</p>
<p>&nbsp;&nbsp;&nbsp; 1. 创建用于配置Log4J环境的Servlet</p>
<div class="code_title">java 代码</div>
<div class="dp-highlighter">
<div class="bar">
<ol class="dp-j">
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;javax.servlet.*; &nbsp;&nbsp;</span></span>
    <li><span><span class="keyword">import</span><span>&nbsp;javax.servlet.http.*; &nbsp;&nbsp;</span>
    <li class="alt"><span><span class="keyword">import</span><span>&nbsp;java.io.*; &nbsp;&nbsp;</span>
    <li><span><span class="keyword">import</span><span>&nbsp;java.util.*; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li><span><span class="keyword">import</span><span>&nbsp;org.apache.log4j.PropertyConfigurator; &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span>
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Log4JServlet&nbsp;</span><span class="keyword">extends</span><span>&nbsp;HttpServlet&nbsp;{ &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;init()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ServletException&nbsp;{ &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;path&nbsp;=&nbsp;getServletContext().getRealPath(</span><span class="string">"/"</span><span>); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//getInitParameter("propfile")方法从web.xml文件中读取Log4J配置文件的名字"profile"。 </span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;propfile&nbsp;=&nbsp;path&nbsp;+&nbsp;getInitParameter(</span><span class="string">"propfile"</span><span>); &nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(propfile); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li class="alt"><span>} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 该Servlet在web.xml中的配置如下：<br />
</p>
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar">
<ol class="dp-xml">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">servlet</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">servlet-name</span><span class="tag">&gt;</span><span>log4jServlet</span><span class="tag">&lt;/</span><span class="tag-name">servlet-name</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">servlet-class</span><span class="tag">&gt;</span><span>Log4JServlet</span><span class="tag">&lt;/</span><span class="tag-name">servlet-class</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">init-param</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">param-name</span><span class="tag">&gt;</span><span>propfile</span><span class="tag">&lt;/</span><span class="tag-name">param-name</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">param-value</span><span class="tag">&gt;</span><span>/WEB-INF/log4j.properties</span><span class="tag">&lt;/</span><span class="tag-name">param-value</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">init-param</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">load-on-startup</span><span class="tag">&gt;</span><span>1</span><span class="tag">&lt;/</span><span class="tag-name">load-on-startup</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span><span class="tag">&lt;/</span><span class="tag-name">servlet</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p>2. 在login.jsp中输出日志<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#37;&#64;&#112;&#97;&#103;&#101;"><font color="#73af1d">%@page</font></a> import="org.apache.log4j.Logger"%&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;html&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;head&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;title&gt;login&lt;/title&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/head&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;body&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;%<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger myLogger = Logger.getLogger("myLogger");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.debug("Thie is a log message from the " + myLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.info("Thie is a log message from the " + myLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.warn("Thie is a log message from the " +&nbsp; myLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.error("Thie is a log message from the " + myLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; myLogger.fatal("Thie is a log message from the " + myLogger.getName());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger.warn("Thie is a log message from the " +&nbsp; mySonLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; %&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;form name="loginForm" method="post" action="dispatcher"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; username: &lt;input type="text" name="username"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; password: &lt;input type="text" name="password"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;br&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;input type="submit" name="submit" value="submit"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/form&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/body&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/html&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; 3. 发布运行使用Log4J的web应用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1) 将Log4J的JAR文件拷贝至目录：&lt;WEB应用所在目录&gt;/WEB-INF/lib<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2) 创建Log4J的配置文件log4j.properties, 存放目录为：&lt;WEB应用所在目录&gt;/WEB-INF。内容同前面配置文件示例。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3) 编译Log4JServlet, 存放至目录： &lt;WEB应用所在目录&gt;/WEB-INF/classes<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4) 修改web.xml文件，加入以下内容：<br />
</p>
<div class="code_title">xml 代码</div>
<div class="dp-highlighter">
<div class="bar">
<ol class="dp-xml">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">servlet</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">servlet-name</span><span class="tag">&gt;</span><span>log4jServlet</span><span class="tag">&lt;/</span><span class="tag-name">servlet-name</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">servlet-class</span><span class="tag">&gt;</span><span>Log4JServlet</span><span class="tag">&lt;/</span><span class="tag-name">servlet-class</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">init-param</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">param-name</span><span class="tag">&gt;</span><span>profile</span><span class="tag">&lt;/</span><span class="tag-name">param-name</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">param-value</span><span class="tag">&gt;</span><span>/WEB-INF/log4j.properties</span><span class="tag">&lt;/</span><span class="tag-name">param-value</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="tag">&lt;/</span><span class="tag-name">init-param</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">load-on-startup</span><span class="tag">&gt;</span><span>1</span><span class="tag">&lt;/</span><span class="tag-name">load-on-startup</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span>
    <li class="alt"><span><span class="tag">&lt;/</span><span class="tag-name">servlet</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span> </li>
</ol>
</div>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5) 启动服务器，访问login.jsp页面，在服务器控制台上看到如下日志：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 另在&lt;WEB应用所在目录&gt;/WEB-INF目录下看到一个log.txt文件，内容如下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ERROR - Thie is a log message from the myLogger.mySonLogger<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FATAL - Thie is a log message from the myLogger.mySonLogger</p>
</span></div>
</span></div>
</span></span></span></span></span></div>
</div>
</span></div>
</div>
<img src ="http://www.blogjava.net/lanxin1020/aggbug/268850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-04 17:19 <a href="http://www.blogjava.net/lanxin1020/archive/2009/05/04/268850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268815.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Mon, 04 May 2009 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268815.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/268815.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268815.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/268815.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/268815.html</trackback:ping><description><![CDATA[<p>在实际编程时，要使<span class="hilite1">Log4j</span>真正在系统中运行事先还要对配置文件进行定义。定义步骤就是对Logger、Appender及Layout的分别使用。<br />
&nbsp; <span class="hilite1">Log4j</span>支持两种配置文件格式，一种是XML格式的文件，一种是java properties（key=value）【Java特性文件（键=值）】。下面我们介绍使用Java特性文件做为配置文件的方法<br />
&nbsp; 具体如下：<br />
　　<br />
　　<strong><span style="color: #ff6600">1、配置根Logger</span> ，</strong> 其语法为：<br />
　　<span class="hilite1">log4j</span>.rootLogger = [ level ] , appenderName1, appenderName2, &#8230;<br />
&nbsp; level : 是日志记录的优先级，分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。<span class="hilite1">Log4j</span>建议只使用四个级别，优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别，您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别，则应用程序中所有DEBUG级别的日志信息将不被打印出来。<br />
　　appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。<br />
&nbsp; 例如：<span class="hilite1">log4j</span>.rootLogger＝info,A1,B2,C3<br />
　　<br />
　　<strong><span style="color: #ff3300">2、配置日志信息输出目的地</span> </strong>，其语法为：<br />
　　<span class="hilite1">log4j</span>.appender.appenderName = fully.qualified.name.of.appender.class &nbsp; //<br />
　　 &nbsp; "fully.qualified.name.of.appender.class" 可以指定下面五个目的地中的一个：<br />
&nbsp; &nbsp; &nbsp; 1.org.apache.<span class="hilite1">log4j</span>.ConsoleAppender（控制台）<br />
&nbsp; &nbsp; &nbsp; 2.org.apache.<span class="hilite1">log4j</span>.FileAppender（文件）<br />
&nbsp; &nbsp; &nbsp; 3.org.apache.<span class="hilite1">log4j</span>.DailyRollingFileAppender（每天产生一个日志文件）<br />
&nbsp; &nbsp; &nbsp; 4.org.apache.<span class="hilite1">log4j</span>.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件）<br />
&nbsp; &nbsp; &nbsp; 5.org.apache.<span class="hilite1">log4j</span>.WriterAppender（将日志信息以流格式发送到任意指定的地方）<br />
&nbsp; &nbsp; &nbsp; &nbsp; <strong><span style="color: #ccff00"><span style="color: #0000ff">1.ConsoleAppender选项</span><br />
</span></strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Threshold=WARN:指定日志消息的输出最低层次。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Target=System.err：默认情况下是：System.out,指定输出控制台<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ccff00"><span style="color: #0000ff"><strong>2.FileAppender</strong> 选项</span><br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Threshold=WARN:指定日志消息的输出最低层次。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File=mylog.txt:指定消息输出到mylog.txt文件。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Append=false:默认值是true,即将消息增加到指定文件中，false指将消息覆盖指定的文件内容。<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff">3.<strong>DailyRollingFileAppender</strong> 选项</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Threshold=WARN:指定日志消息的输出最低层次。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File=mylog.txt:指定消息输出到mylog.txt文件。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Append=false:默认值是true,即将消息增加到指定文件中，false指将消息覆盖指定的文件内容。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DatePattern='.'yyyy-ww:每周滚动一次文件，即每周产生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下：<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1)'.'yyyy-MM: 每月<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2)'.'yyyy-ww: 每周 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3)'.'yyyy-MM-dd: 每天<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4)'.'yyyy-MM-dd-a: 每天两次<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 5)'.'yyyy-MM-dd-HH: 每小时<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 6)'.'yyyy-MM-dd-HH-mm: 每分钟<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ccff00"><span style="color: #0000ff">4.<strong>RollingFileAppender</strong> 选项</span><br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Threshold=WARN:指定日志消息的输出最低层次。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; File=mylog.txt:指定消息输出到mylog.txt文件。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Append=false:默认值是true,即将消息增加到指定文件中，false指将消息覆盖指定的文件内容。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时，将会自动滚动，即将原来的内容移到mylog.log.1文件。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MaxBackupIndex=2:指定可以产生的滚动文件的最大数。 实际应用：<br />
　　<span class="hilite1">log4j</span>.appender.A1=org.apache.<span class="hilite1">log4j</span>.ConsoleAppender //这里指定了日志输出的第一个位置A1是控制台ConsoleAppender<br />
　　<br />
　　<span style="color: #ff6600"><strong>3、配置日志信息的格式</strong> ，</span> 其语法为：<br />
　　<strong>A.</strong> <strong><span class="hilite1">log4j</span>.appender.appenderName.layout = fully.qualified.name.of.layout.class<br />
</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个：<br />
&nbsp; &nbsp; &nbsp; &nbsp; 1.org.apache.<span class="hilite1">log4j</span>.HTMLLayout（以HTML表格形式布局），<br />
　　 &nbsp; &nbsp; 2.org.apache.<span class="hilite1">log4j</span>.PatternLayout（可以灵活地指定布局模式），<br />
　　 &nbsp; &nbsp; 3.org.apache.<span class="hilite1">log4j</span>.SimpleLayout（包含日志信息的级别和信息字符串），<br />
　　 &nbsp; &nbsp; 4.org.apache.<span class="hilite1">log4j</span>.TTCCLayout（包含日志产生的时间、线程、类别等等信息）<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1.HTMLLayout 选项<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LocationInfo=true:默认值是false,输出java文件名称和行号<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Title=my app file: 默认值是 <span class="hilite1">Log4J</span> Log Messages.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2.PatternLayout 选项<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ConversionPattern=%m%n :指定怎样格式化指定的消息。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3.XMLLayout &nbsp; 选项<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LocationInfo=true:默认值是false,输出java文件和行号<br />
&nbsp; 实际应用：<br />
&nbsp; 　　<span class="hilite1">log4j</span>.appender.A1.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout<br />
&nbsp; &nbsp; <strong>B</strong> .<strong> <span class="hilite1">log4j</span>.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n<br />
</strong>&nbsp; &nbsp; &nbsp; &nbsp; 这里需要说明的就是日志信息格式中几个符号所代表的含义：<br />
　　 &nbsp; &nbsp; &nbsp; －X号: X信息输出时左对齐；<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %p: 输出日志信息优先级，即DEBUG，INFO，WARN，ERROR，FATAL,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %d: 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyy MMM dd HH:mm:ss,SSS}，输出类似：2002年10月18日 22：10：28，921<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %r: 输出自应用启动到输出该log信息耗费的毫秒数<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %c: 输出日志信息所属的类目，通常就是所在类的全名<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %t: 输出产生该日志事件的线程名<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %l: 输出日志事件的发生位置，相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程，以及在代码中的行数。举例：Testlog4.main(TestLog4.java:10)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %%: 输出一个"%"字符<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %F: 输出日志消息产生时所在的文件名称<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %L: 输出代码中的行号<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %m: 输出代码中指定的消息,产生的日志具体信息<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %n: 输出一个回车换行符，Windows平台为"\r\n"，Unix平台为"\n"输出日志信息换行<br />
&nbsp; &nbsp; &nbsp; &nbsp; 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如：<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1)%20c：指定输出category的名称，最小的宽度是20，如果category的名称小于20的话，默认的情况下右对齐。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2)%-20c:指定输出category的名称，最小的宽度是20，如果category的名称小于20的话，"-"号指定左对齐。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3)%.30c:指定输出category的名称，最大的宽度是30，如果category的名称大于30的话，就会将左边多出的字符截掉，但小于30的话也不会有空格。<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4)%20.30c:如果category的名称小于20就补空格，并且右对齐，如果其名称长于30字符，就从左边交远销出的字符截掉。<br />
　　这里上面三个步骤是对前面<span class="hilite1">Log4j</span>组件说明的一个简化；下面给出一个具体配置例子，在程序中可以参照执行：<br />
　　<span class="hilite1">log4j</span>.rootLogger=INFO,A1，B2<br />
　　<span class="hilite1">log4j</span>.appender.A1=org.apache.<span class="hilite1">log4j</span>.ConsoleAppender<br />
　　<span class="hilite1">log4j</span>.appender.A1.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout<br />
　　<span class="hilite1">log4j</span>.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n<br />
　　根据上面的日志格式，某一个程序的输出结果如下：<br />
　　0　　INFO　2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]<br />
&nbsp; 16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with <span class="hilite1">log4j</span>, Fri Jun 13 13:23:46 CST 2003'<br />
　　16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD<br />
　　16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'<br />
　　16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP<br />
　　16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'<br />
　　16　 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT<br />
<br />
&nbsp; <strong><span style="color: #ff6600">4. # 当输出信息于回滚文件时</span> </strong><br />
&nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE=org.apache.<span class="hilite1">log4j</span>.RollingFileAppender &nbsp; //指定以文件的方式输出日志<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.Threshold=ERROR <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.File=rolling.log &nbsp; //文件位置,也可以用变量${java.home}、rolling.log<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.Append=true <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.MaxFileSize=10KB &nbsp; //文件最大尺寸<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.MaxBackupIndex=1 &nbsp; //备份数<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="hilite1">log4j</span>.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n &nbsp; 　　<br />
&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;&#215;<br />
<strong><span style="color: #0000ff"><br />
</span></strong><strong><span style="color: #0000ff">附：<span class="hilite1">Log4j</span>比较全面的配置</span> </strong><br />
<span class="hilite1">LOG4J</span>的配置之简单使它遍及于越来越多的应用中了：<span class="hilite1">Log4J</span>配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。择其一二使用就够用了， <br />
<span class="hilite1">log4j</span>.rootLogger=DEBUG,CONSOLE,A1,im <br />
<span class="hilite1">log4j</span>.addivity.org.apache=true <br />
# 应用于控制台 <br />
<span class="hilite1">log4j</span>.appender.CONSOLE=org.apache.<span class="hilite1">log4j</span>.ConsoleAppender <br />
<span class="hilite1">log4j</span>.appender.Threshold=DEBUG <br />
<span class="hilite1">log4j</span>.appender.CONSOLE.Target=System.out <br />
<span class="hilite1">log4j</span>.appender.CONSOLE.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />
#<span class="hilite1">log4j</span>.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n <br />
#应用于文件 <br />
<span class="hilite1">log4j</span>.appender.FILE=org.apache.<span class="hilite1">log4j</span>.FileAppender <br />
<span class="hilite1">log4j</span>.appender.FILE.File=file.log <br />
<span class="hilite1">log4j</span>.appender.FILE.Append=false <br />
<span class="hilite1">log4j</span>.appender.FILE.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />
# Use this layout for LogFactor 5 analysis <br />
# 应用于文件回滚 <br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE=org.apache.<span class="hilite1">log4j</span>.RollingFileAppender <br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.Threshold=ERROR <br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.File=rolling.log &nbsp; //文件位置,也可以用变量${java.home}、rolling.log<br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.Append=true &nbsp; &nbsp; //true:添加 &nbsp; false:覆盖<br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.MaxFileSize=10KB &nbsp; //文件最大尺寸<br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.MaxBackupIndex=1 &nbsp; //备份数<br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />
<br />
#应用于socket <br />
<span class="hilite1">log4j</span>.appender.SOCKET=org.apache.<span class="hilite1">log4j</span>.RollingFileAppender <br />
<span class="hilite1">log4j</span>.appender.SOCKET.RemoteHost=localhost <br />
<span class="hilite1">log4j</span>.appender.SOCKET.Port=5001 <br />
<span class="hilite1">log4j</span>.appender.SOCKET.LocationInfo=true <br />
# Set up for Log Facter 5 <br />
<span class="hilite1">log4j</span>.appender.SOCKET.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n <br />
<br />
# Log Factor 5 Appender <br />
<span class="hilite1">log4j</span>.appender.LF5_APPENDER=org.apache.<span class="hilite1">log4j</span>.lf5.LF5Appender <br />
<span class="hilite1">log4j</span>.appender.LF5_APPENDER.MaxNumberOfRecords=2000 <br />
# 发送日志给邮件 <br />
<span class="hilite1">log4j</span>.appender.MAIL=org.apache.<span class="hilite1">log4j</span>.net.SMTPAppender <br />
<span class="hilite1">log4j</span>.appender.MAIL.Threshold=FATAL <br />
<span class="hilite1">log4j</span>.appender.MAIL.BufferSize=10 <br />
<span class="hilite1">log4j</span>.appender.MAIL.From=web@<a href="http://www.wuset.com/" target="_blank"><span style="text-decoration: underline"><span style="color: #4d6c80">www.wuset.com</span><span style="color: #108ac6"> </span></span></a><br />
<span class="hilite1">log4j</span>.appender.MAIL.SMTPHost=www.wusetu.com <br />
<span class="hilite1">log4j</span>.appender.MAIL.Subject=<span class="hilite1">Log4J</span> Message <br />
<span class="hilite1">log4j</span>.appender.MAIL.To=web@<a href="http://www.wusetu.com/" target="_blank"><span style="text-decoration: underline"><span style="color: #4d6c80">www.wusetu.com</span><span style="color: #108ac6"> </span></span></a><br />
<span class="hilite1">log4j</span>.appender.MAIL.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />
# 用于数据库 <br />
<span class="hilite1">log4j</span>.appender.DATABASE=org.apache.<span class="hilite1">log4j</span>.jdbc.JDBCAppender <br />
<span class="hilite1">log4j</span>.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test <br />
<span class="hilite1">log4j</span>.appender.DATABASE.driver=com.mysql.jdbc.Driver <br />
<span class="hilite1">log4j</span>.appender.DATABASE.user=root <br />
<span class="hilite1">log4j</span>.appender.DATABASE.password= <br />
<span class="hilite1">log4j</span>.appender.DATABASE.sql=INSERT INTO <span class="hilite1">LOG4J</span> (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n') <br />
<span class="hilite1">log4j</span>.appender.DATABASE.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n <br />
<br />
<span class="hilite1">log4j</span>.appender.A1=org.apache.<span class="hilite1">log4j</span>.DailyRollingFileAppender <br />
<span class="hilite1">log4j</span>.appender.A1.File=SampleMessages.<span class="hilite1">log4j</span> <br />
<span class="hilite1">log4j</span>.appender.A1.DatePattern=yyyyMMdd-HH'.<span class="hilite1">log4j</span>' <br />
<span class="hilite1">log4j</span>.appender.A1.layout=org.apache.<span class="hilite1">log4j</span>.xml.XMLLayout <br />
#自定义Appender <br />
<span class="hilite1">log4j</span>.appender.im = net.cybercorlin.util.logger.appender.IMAppender <br />
<span class="hilite1">log4j</span>.appender.im.host = mail.cybercorlin.net <br />
<span class="hilite1">log4j</span>.appender.im.username = username <br />
<span class="hilite1">log4j</span>.appender.im.password = password <br />
<span class="hilite1">log4j</span>.appender.im.recipient = <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#99;&#111;&#114;&#108;&#105;&#110;&#64;&#99;&#121;&#98;&#101;&#114;&#99;&#111;&#114;&#108;&#105;&#110;&#46;&#110;&#101;&#116;"><span style="text-decoration: underline"><span style="color: #4d6c80">corlin@cybercorlin.net</span><span style="color: #108ac6"> </span></span></a><br />
<span class="hilite1">log4j</span>.appender.im.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout <br />
<span class="hilite1">log4j</span>.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n</p>
<img src ="http://www.blogjava.net/lanxin1020/aggbug/268815.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-04 14:40 <a href="http://www.blogjava.net/lanxin1020/archive/2009/05/04/268815.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268813.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Mon, 04 May 2009 06:37:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268813.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/268813.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/05/04/268813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/268813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/268813.html</trackback:ping><description><![CDATA[<span class="hilite1">Log4j</span>下载 <br />
在apache网站：jakarta.apache.org/<span class="hilite1">log4j</span> 可以免费下载到<span class="hilite1">Log4j</span>最新版本的软件包。 <br />
<br />
<span class="hilite1">Log4j</span>使用 <br />
<span class="hilite1">Log4j</span>的包下载完成后，解压，将其中打包好的的<span class="hilite1">log4j</span>-1.x.x.jar导入你的工程LIB中。 <br />
<span class="hilite1">Log4j</span>之所以受欢迎的原因之一是它的灵活性。<span class="hilite1">Log4j</span>提供了灵活的配置方法，默认是调用BasicConfigurator.configure()来进行配置，但如果只是简单的调用BasicConfigurator.configure()来进行配置工作，那么所有的配置都是固定的，不方便以后修改配置。另一种是动态配置，<span class="hilite1">Log4j</span>提供了PropertyConfigurator.configure(&#8230;&#8230;)来动态配置，参数可以是一个properties文件所在路径的String对象，可以是一个properties文件所在路径的URL对象，也可以是一个properties对象。如果要用XML文件来配置信息，则可用类型的DOMConfigurator()函数来从一个XML文件中加载配置信息。这种方式更方便修改配置。 <br />
<br />
动态配置 <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">package</span><span>&nbsp;http;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.<span class="hilite1">log4j</span>.BasicConfigurator;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.<span class="hilite1">log4j</span>.Logger;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.<span class="hilite1">log4j</span>.PropertyConfigurator;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.<span class="hilite1">log4j</span>.xml.DOMConfigurator;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;Log4jDemo&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">static</span><span>&nbsp;Logger&nbsp;log&nbsp;=&nbsp;Logger.getLogger(Log4jDemo.</span><span class="keyword">class</span><span>.getClass());&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/**&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;main&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;args&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></li>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BasicConfigurator.configure();</span><span class="comment">//默认配置&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(</span><span class="string">"c:/<span class="hilite1">log4j</span>.properties"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//动态配置,参数可以是一个properties文件所在路径的String对象&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//可以是一个properties文件所在路径的URL对象，也可以是一个properties对象&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DOMConfigurator.configure(</span><span class="string">"c:/<span class="hilite1">log4j</span>.xml"</span><span>);</span><span class="comment">//XML配置文件&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//PropertyConfigurator.configure()的参数还可以是XML、Properties对象&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//下面就可使用<span class="hilite1">log4j</span>&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(</span><span class="string">"info"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</span><span class="string">"debug"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error(</span><span class="string">"error"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.warn(</span><span class="string">"warn"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">package http;
import org.apache.<span class="hilite1">log4j</span>.BasicConfigurator;
import org.apache.<span class="hilite1">log4j</span>.Logger;
import org.apache.<span class="hilite1">log4j</span>.PropertyConfigurator;
import org.apache.<span class="hilite1">log4j</span>.xml.DOMConfigurator;
public class Log4jDemo {
static Logger log = Logger.getLogger(Log4jDemo.class.getClass());
/**
* main
* @param args
*/
public static void main(String[] args) {
BasicConfigurator.configure();//默认配置
PropertyConfigurator.configure("c:/<span class="hilite1">log4j</span>.properties");
//动态配置,参数可以是一个properties文件所在路径的String对象
//可以是一个properties文件所在路径的URL对象，也可以是一个properties对象
DOMConfigurator.configure("c:/<span class="hilite1">log4j</span>.xml");//XML配置文件
//PropertyConfigurator.configure()的参数还可以是XML、Properties对象
//下面就可使用<span class="hilite1">log4j</span>
log.info("info");
log.debug("debug");
log.error("error");
log.warn("warn");
}
}
</pre>
<br />
<br />
J2EE应用<span class="hilite1">log4j</span> <br />
上面代码描述了<span class="hilite1">Log4j</span>的简单应用，其实使用<span class="hilite1">Log4j</span>也就是这样简单方便。当然除了上面的配置方法，还有其它，比如做一个J2EE应用，在J2EE应用使用<span class="hilite1">Log4j</span>，必须先在启动服务时加载<span class="hilite1">Log4j</span>的配置文件进行初始化，可以在web.xml中进行。 <br />
<br />
<br />
java 代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">import</span><span>&nbsp;java.io.IOException;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;java.io.PrintWriter;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.servlet.ServletException;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.servlet.http.HttpServlet;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.servlet.http.HttpServletRequest;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">import</span><span>&nbsp;javax.servlet.http.HttpServletResponse;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;J2eeLog4jDemo&nbsp;</span><span class="keyword">extends</span><span>&nbsp;HttpServlet&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;destroy()&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">super</span><span>.destroy();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;doGet(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ServletException,&nbsp;IOException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;doPost(HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ServletException,&nbsp;IOException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;init()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;ServletException&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//通过web.xml来动态取得配置文件&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;prefix&nbsp;=&nbsp;getServletContext().getRealPath(</span><span class="string">"/"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;file&nbsp;=&nbsp;getInitParameter(</span><span class="string">"<span class="hilite1">log4j</span>"</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//如果没有给出相应的配置文件，则不进行初始化&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(file&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyConfigurator.configure(prefix+file);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class J2eeLog4jDemo extends HttpServlet {
public void destroy() {
super.destroy();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
public void init() throws ServletException {
//通过web.xml来动态取得配置文件
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("<span class="hilite1">log4j</span>");
//如果没有给出相应的配置文件，则不进行初始化
if(file != null)
{
PropertyConfigurator.configure(prefix+file);
}
}
}
</pre>
<br />
Web.xml 代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;servlet&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;servlet-name&gt;j2eelog4jdemoservlet-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;servlet-</span><span class="keyword">class</span><span>&gt;J2eeLog4jDemoservlet-</span><span class="keyword">class</span><span>&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;init-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;param-name&gt;log4jparam-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;param-value&gt;<span class="hilite1">log4j</span>.propertiesparam-value&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>init-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;load-on-startup&gt;1load-on-startup&gt;&nbsp;&nbsp;</span><span class="comment">//设为1时，Web容器启动即进行加载&nbsp; </span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>servlet&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">&lt;servlet&gt;
&lt;servlet-name&gt;j2eelog4jdemoservlet-name&gt;
&lt;servlet-class&gt;J2eeLog4jDemoservlet-class&gt;
&lt;init-param&gt;
&lt;param-name&gt;log4jparam-name&gt;
&lt;param-value&gt;<span class="hilite1">log4j</span>.propertiesparam-value&gt;
init-param&gt;
&lt;load-on-startup&gt;1load-on-startup&gt;  //设为1时，Web容器启动即进行加载
servlet
</pre>
<br />
<br />
Spring<span class="hilite2">配置</span><span class="hilite1">Log4j</span> <br />
Spring中配置<span class="hilite1">Log4j</span>只要配置applicationContext.xml文件，<span class="hilite1">Log4j</span>的配置文件放在Web工程的根目录下，默认是objectname/root下,可以在web.xml中设置工程根目录. <br />
<br />
设置根目录 <br />
<br />
<br />
web.xml 代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;!--不定义webAppRootKey参数，webAppRootKey就是缺省的</span><span class="string">"webapp.root"</span><span>--&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&lt;context-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&lt;param-name&gt;webAppRootKeyparam-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&lt;param-value&gt;webapp.rootparam-value&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;context-param&gt;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">&lt;!--不定义webAppRootKey参数，webAppRootKey就是缺省的"webapp.root"--&gt;
&lt;context-param&gt;
&lt;param-name&gt;webAppRootKeyparam-name&gt;
&lt;param-value&gt;webapp.rootparam-value&gt;
context-param&gt;
</pre>
<br />
<br />
配置applicationContext.xml <br />
<br />
<br />
applicationContext.xml 代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;!--由Sprng载入的<span class="hilite1">Log4j</span>配置文件位置--&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&lt;context-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;param-name&gt;log4jConfigLocationparam-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;param-value&gt;/WEB-INF/<span class="hilite1">log4j</span>.propertiesparam-value&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;!--在这里定位配置文件，需要的是从root开始的绝对路径--&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>context-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;!--Spring默认刷新<span class="hilite1">Log4j</span>配置文件的间隔,单位为millisecond--&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;context-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;param-name&gt;log4jRefreshIntervalparam-name&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;param-value&gt;60000param-value&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>context-param&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;!--Spring&nbsp;<span class="hilite1">log4j</span>&nbsp;监听器--&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&lt;listener&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&lt;listener-</span><span class="keyword">class</span><span>&gt;org.springframework.web.util.Log4jConfigListenerlistener-</span><span class="keyword">class</span><span>&gt;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>listener&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">&lt;!--由Sprng载入的<span class="hilite1">Log4j</span>配置文件位置--&gt;
&lt;context-param&gt;
&lt;param-name&gt;log4jConfigLocationparam-name&gt;
&lt;param-value&gt;/WEB-INF/<span class="hilite1">log4j</span>.propertiesparam-value&gt;
&lt;!--在这里定位配置文件，需要的是从root开始的绝对路径--&gt;
context-param&gt;
&lt;!--Spring默认刷新<span class="hilite1">Log4j</span>配置文件的间隔,单位为millisecond--&gt;
&lt;context-param&gt;
&lt;param-name&gt;log4jRefreshIntervalparam-name&gt;
&lt;param-value&gt;60000param-value&gt;
context-param&gt;
&lt;!--Spring <span class="hilite1">log4j</span> 监听器--&gt;
&lt;listener&gt;
&lt;listener-class&gt;org.springframework.web.util.Log4jConfigListenerlistener-class&gt;
listener&gt;
</pre>
<br />
<br />
同时使用commons-logging和<span class="hilite1">Log4j</span> <br />
<br />
<br />
1)首先在classpath下寻找自己的配置文件commons-logging.properties，如果找到，则使用其中定义的Log实现类 <br />
2)如果找不到commons-logging.properties文件，则在查找是否已定义系统环境变量org.apache.commons.logging.Log，找到则使用其定义的Log实现类 <br />
3)否则，查看classpath中是否有<span class="hilite1">Log4j</span>的包，如果发现，则自动使用<span class="hilite1">Log4j</span>作为日志实现类 <br />
4)否则，使用JDK自身的日志实现类（JDK1.4以后才有日志实现类） <br />
5)否则，使用commons-logging自己提供的一个简单的日志实现类SimpleLog <br />
<br />
<br />
将commons-logging和<span class="hilite1">Log4j</span>的jar包都放置到classpath下，同时也将<span class="hilite1">Log4j</span>的配置文件放到classpath中，两者就可以很好的合作,实现如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">package</span><span>&nbsp;com.doctorcom.model;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">import</span><span>&nbsp;org.apache.commons.logging.Log;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;LogFactorySupport&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Log&nbsp;getLog(){&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Log&nbsp;log&nbsp;=&nbsp;org.apache.commons.logging.LogFactory.getLog(LogFactorySupport.</span><span class="keyword">class</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(</span><span class="string">""</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug(</span><span class="string">""</span><span>);&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">package com.doctorcom.model;
import org.apache.commons.logging.Log;
public class LogFactorySupport {
public Log getLog(){
Log log = org.apache.commons.logging.LogFactory.getLog(LogFactorySupport.class);
log.info("");
log.debug("");
}
}
</pre>
<br />
<br />
java 代码 <br />
<br />
<span class="hilite1">Log4j</span>配置内容 <br />
看一个简单的java属性配置文件<span class="hilite1">log4j</span>.properties： <br />
<br />
properties 代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>#指定根Logger，及日志输出级别，大于等于该级别的日志将被输出（&nbsp;DEBUG&nbsp;&lt;&nbsp;INFO&nbsp;&lt;&nbsp;WARN&nbsp;&lt;&nbsp;ERROR&nbsp;&lt;&nbsp;FATAL&nbsp;）&nbsp;设为OFF可以关闭日志&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li><span><span class="hilite1">log4j</span>.rootLogger=DEBUG,&nbsp;A1,A2&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>#指定log输出目的,这里设为输出日志到指定目录的文件my.log中&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A1=org.apache.<span class="hilite1">log4j</span>.FileAppender&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A1.File=\\logs\\my.log&nbsp;&nbsp;&nbsp;#当前根目录下&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>#指定日志信息的格式&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A1.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A1.layout.ConversionPattern=%r&nbsp;%d{yyyy-MM-dd&nbsp;HH:mm:ss}&nbsp;%c&nbsp;%p&nbsp;-%m%n&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>#把A2输出到控制台&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A2=org.apache.<span class="hilite1">log4j</span>.ConsoleAppender&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span><span class="hilite1">log4j</span>.appender.A2.layout=org.apache.<span class="hilite1">log4j</span>.SimpleLayout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>#还可以单独指定输出某个包的日志级别&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>#<span class="hilite1">log4j</span>.logger.com.study.HelloLog4j=INFO&nbsp;&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre style="display: none" class="java" name="code">#指定根Logger，及日志输出级别，大于等于该级别的日志将被输出（ DEBUG &lt; INFO &lt; WARN &lt; ERROR &lt; FATAL ） 设为OFF可以关闭日志
<span class="hilite1">log4j</span>.rootLogger=DEBUG, A1,A2
#指定log输出目的,这里设为输出日志到指定目录的文件my.log中
<span class="hilite1">log4j</span>.appender.A1=org.apache.<span class="hilite1">log4j</span>.FileAppender
<span class="hilite1">log4j</span>.appender.A1.File=\\logs\\my.log   #当前根目录下
#指定日志信息的格式
<span class="hilite1">log4j</span>.appender.A1.layout=org.apache.<span class="hilite1">log4j</span>.PatternLayout
<span class="hilite1">log4j</span>.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n
#把A2输出到控制台
<span class="hilite1">log4j</span>.appender.A2=org.apache.<span class="hilite1">log4j</span>.ConsoleAppender
<span class="hilite1">log4j</span>.appender.A2.layout=org.apache.<span class="hilite1">log4j</span>.SimpleLayout
#还可以单独指定输出某个包的日志级别
#<span class="hilite1">log4j</span>.logger.com.study.HelloLog4j=INFO
</pre>
<br />
<br />
1、配置根Logger，其语法为： <br />
<span class="hilite1">log4j</span>.rootLogger = [ level ] , appenderName, appenderName2 <br />
level：日志的级别，指定这条日志信息的重要性。分为ALL &lt; DEBUG &lt; INFO &lt; WARN &lt;error fatal=""&gt;&lt;/error&gt;一般常用的为 DEBUG ， INFO ，WARN ，ERROR四种，分别对应Logger类的四种方法 <br />
debug(Object message ) ; <br />
info(Object message ) ; <br />
warn(Object message ) ; <br />
error(Object message ) ; <br />
如果设置级别为INFO，则优先级大于等于INFO级别（如：INFO、WARN、ERROR）的日志信息将可以被输出,小于该级别的如：DEBUG将不会被输出 <br />
appenderName :就是指定日志信息输出目的地，比如（打印到控制台，输出到文件等）。同一条日志信息可以配置多个输出目的地。 <br />
<br />
2、配置log输出目的地 <br />
<span class="hilite1">Log4j</span>提供以下几种： <br />
org.apache.<span class="hilite1">log4j</span>.ConsoleAppender（控制台） <br />
org.apache.<span class="hilite1">log4j</span>.FileAppender（文件） <br />
org.apache.<span class="hilite1">log4j</span>.DailyRollingFileAppender（每天产生一个日志文件） <br />
org.apache.<span class="hilite1">log4j</span>.RollingFileAppender（文件大小到达指定尺寸的时候产生一个新的文件） <br />
org.apache.<span class="hilite1">log4j</span>.WriterAppender（将日志信息以流格式发送到任意指定的地方） <br />
3、log信息的格式 <br />
org.apache.<span class="hilite1">log4j</span>.HTMLLayout（HTML表格形式） <br />
org.apache.<span class="hilite1">log4j</span>.SimpleLayout（简单格式的日志，只包括日志信息的级别和指定的信息字符串 ，如:DEBUG - Hello） <br />
org.apache.<span class="hilite1">log4j</span>.TTCCLayout（日志的格式包括日志产生的时间、线程、类别等等信息） <br />
org.apache.<span class="hilite1">log4j</span>.PatternLayout（灵活地自定义日志格式） <br />
<br />
当使用org.apache.<span class="hilite1">log4j</span>.PatternLayout来自定义信息格式时，可以使用 <br />
<span class="hilite1">log4j</span>.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p -%m%n 来格式化信息 <br />
%c&nbsp;&nbsp;&nbsp; 输出所属类的全名，可写为 %c{Num} ,Num类名输出的范围&nbsp; 如："com.sun.aaa.classB", %C{2}将使日志输出输出范围为：aaa.classB <br />
%d&nbsp;&nbsp;&nbsp; 输出日志时间其格式为 可指定格式 如 %d{HH:mm:ss}等 <br />
%l&nbsp;&nbsp;&nbsp; 输出日志事件发生位置，包括类目名、发生线程，在代码中的行数 <br />
%n&nbsp;&nbsp;&nbsp; 换行符 <br />
%m&nbsp;&nbsp;&nbsp; 输出代码指定信息，如info(&#8220;message&#8221;),输出message <br />
%p&nbsp;&nbsp;&nbsp; 输出日志的优先级，即 FATAL ,ERROR 等 <br />
%r&nbsp;&nbsp;&nbsp; 输出从启动到显示该条日志信息所耗费的时间（毫秒数） <br />
%t&nbsp;&nbsp;&nbsp; 输出产生该日志事件的线程名 <br />
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/268813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-04 14:37 <a href="http://www.blogjava.net/lanxin1020/archive/2009/05/04/268813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>