??xml version="1.0" encoding="utf-8" standalone="yes"?>久久亚洲中文字幕无码,久久久久亚洲AV成人网人人软件,亚洲一级毛片免费在线观看http://m.tkk7.com/lanxin1020/category/39379.htmlzh-cnTue, 12 May 2009 14:15:17 GMTTue, 12 May 2009 14:15:17 GMT60ASM(?http://m.tkk7.com/lanxin1020/archive/2009/05/12/270177.htmllanxin1020lanxin1020Tue, 12 May 2009 04:43:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/05/12/270177.htmlhttp://m.tkk7.com/lanxin1020/comments/270177.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/05/12/270177.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/270177.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/270177.html什么是 ASMQ?/span>

ASM 是一?Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进?class 文gQ也可以在类被加载入 Java 虚拟Z前动态改变类行ؓ。Java class 被存储在严格格式定义?.class 文g里,q些cL件拥有够的元数据来解析cM的所有元素:cdU、方法、属性以?Java 字节码(指oQ。ASM 从类文g中读入信息后Q能够改变类行ؓQ分析类信息Q甚臌够根据用戯求生成新cR?/p>

?BCEL ?SERL 不同QASM 提供了更为现代的~程模型。对?ASM 来说QJava class 被描qCؓ一|Q?“Visitor” 模式遍历整个二进制结构;事g驱动的处理方式得用户只需要关注于对其~程有意义的部分Q而不必了?Java cL件格式的所有细节:ASM 框架提供了默认的 “response taker”处理q一切?/p>

Z么要动态生?Java c?

动态生?Java cM AOP 密切相关的。AOP 的初衷在于Y件设计世界中存在q么一cM码,零散而又耦合Q零散是׃一些公有的功能Q诸如著名的 log 例子Q分散在所有模块之中;同时改变 log 功能又会影响到所有的模块。出现这L~陷Q很大程度上是由于传l的 面向对象~程注重以承关pMؓ代表?#8220;U向”关系Q而对于拥有相同功能或者说斚w QAspectQ的模块之间?#8220;横向”关系不能很好地表达。例如,目前有一个既有的银行理pȝQ包?Bank、Customer、Account、Invoice {对象,现在要加入一个安全检查模块, 对已有类的所有操作之前都必须q行一ơ安全检查?/p>
?1. ASM – AOP
?1. ASM – AOP

然?Bank、Customer、Account、Invoice 是代表不同的事务Q派生自不同的父c,很难在高层上加入关于 Security Checker 的共有功能。对于没有多l承?Java 来说Q更是如此。传l的解决Ҏ是?Decorator 模式Q它可以在一定程度上改善耦合Q而功能仍旧是分散?—?每个需?Security Checker 的类都必要z一?DecoratorQ每个需?Security Checker 的方法都要被包装QwrapQ。下面我们以 Account cMؓ例看一?DecoratorQ?/p>

首先Q我们有一?SecurityChecker c,光态方?checkSecurity 执行安全查功能:

public class SecurityChecker {   public static void checkSecurity() {    System.out.println("SecurityChecker.checkSecurity ...");    //TODO real security check   }   }       

另一个是 Account c:

public class Account {   public void operation() {    System.out.println("operation...");    //TODO real operation   }  }       

若想?operation 加入?SecurityCheck.checkSecurity() 调用Q标准的 Decorator 需要先定义一?Account cȝ接口Q?/p>
public interface Account {   void operation();   }       

然后把原来的 Account cd义ؓ一个实现类Q?/p>
public class AccountImpl extends Account{   public void operation() {    System.out.println("operation...");    //TODO real operation   }  }        

定义一?Account cȝ DecoratorQƈ包装 operation ҎQ?/p>
public class AccountWithSecurityCheck implements Account {    private  Account account;   public AccountWithSecurityCheck (Account account) {    this.account = account;   }   public void operation() {    SecurityChecker.checkSecurity();    account.operation();   }  }       

在这个简单的例子里,攚w一个类的一个方法还好,如果是变动整个模块,Decorator 很快׃演化成另一个噩梦。动态改?Java cd是要解决 AOP 的问题,提供一U得到系l支持的可编E的ҎQ自动化地生成或者增?Java 代码。这U技术已l广泛应用于最新的 Java 框架内,?HibernateQSpring {?/p>

Z么选择 ASMQ?/span>

最直接的改?Java cȝҎ莫过于直接改?class 文g。Java 规范详细说明了class 文g的格式,直接~辑字节码确实可以改?Java cȝ行ؓ。直C天,q有一?Java 高手们用最原始的工P?UltraEdit q样的编辑器?class 文g动手术。是的,q是最直接的方法,但是要求使用者对 Java class 文g的格式了熟于心:心地推出x造的函数相对文g首部的偏U量Q同旉新计?class 文g的校验码以通过 Java 虚拟机的安全机制?/p>

Java 5 中提供的 Instrument 包也可以提供cM的功能:启动时往 Java 虚拟Z挂上一个用户定义的 hook E序Q可以在装入特定cȝ时候改变特定类的字节码Q从而改变该cȝ行ؓ。但是其~点也是明显的:

  • Instrument 包是在整个虚拟机上挂了一个钩子程序,每次装入一个新cȝ时候,都必L行一遍这D늨序,即ɘq个cM需要改变?
  • 直接改变字节码事实上cM于直接改?class 文gQ无论是调用 ClassFileTransformer. transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)Q还?Instrument.redefineClasses(ClassDefinition[] definitions)Q都必须提供?Java cȝ字节码。也是_同直接改?class 文g一P使用 Instrument 也必M解想攚w的Ҏ相对c首部的偏移量,才能在适当的位|上插入新的代码?

管 Instrument 可以攚w类Q但事实上,Instrument 更适用于监控和控制虚拟机的行ؓ?/p>

一U比较理想且行的方法是使用 java.lang.ref.proxy。我们仍旧用上面的例子Q给 Account cd?checkSecurity 功能:

首先QProxy ~程是面向接口的。下面我们会看到QProxy q不负责实例化对象,?Decorator 模式一P要把 Account 定义成一个接口,然后?AccountImpl 里实?Account 接口Q接着实现一?InvocationHandler Account Ҏ被调用的时候,虚拟机都会实际调用这?InvocationHandler ?invoke ҎQ?/p>
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 && method.getName().equals("opertaion")) {     SecurityChecker.checkSecurity();    }    return method.invoke(proxyedObject, arguments);   }  }    

最后,在应用程序中指定 InvocationHandler 生成代理对象Q?/p>
public static void main(String[] args) {   Account account = (Account) Proxy.newProxyInstance(    Account.class.getClassLoader(),    new Class[] { Account.class },    new SecurityProxyInvocationHandler(new AccountImpl())   );   account.function();  }   

其不之处在于:

  • Proxy 是面向接口的Q所有?Proxy 的对象都必须定义一个接口,而且用这些对象的代码也必LҎ口编E的QProxy 生成的对象是接口一致的而不是对象一致的Q例子中 Proxy.newProxyInstance 生成的是实现 Account 接口的对象而不?AccountImpl 的子cR这对于软g架构设计Q尤其对于既有Y件系l是有一定掣肘的?
  • Proxy 毕竟是通过反射实现的,必须在效率上付出代hQ有实验数据表明Q调用反比一般的函数开销臛_要大 10 倍。而且Q从E序实现上可以看出,?proxy class 的所有方法调用都要通过使用反射?invoke Ҏ。因此,对于性能关键的应用,使用 proxy class 是需要精心考虑的,以避免反成为整个应用的瓉?

ASM 能够通过攚w既有类Q直接生成需要的代码。增强的代码是硬~码在新生成的类文g内部的,没有反射带来性能上的付出。同ӞASM ?Proxy ~程不同Q不需要ؓ增强代码而新定义一个接口,生成的代码可以覆盖原来的c,或者是原始cȝ子类。它是一个普通的 Java c而不?proxy c,甚至可以在应用程序的cL架中拥有自己的位|,z自己的子cR?/p>

相比于其他流行的 Java 字节码操U工PASM 更小更快。ASM hcM?BCEL 或?SERP 的功能,而只?33k 大小Q而后者分别有 350k ?150k。同Ӟ同样c{换的负蝲Q如?ASM ?60% 的话QBCEL 需?700%Q?SERP 需?1100% 或者更多?/p>

ASM 已经被广泛应用于一pd Java 目QAspectWerkz、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&F、Retrotranslator {。Hibernate ?Spring 也通过 cglibQ另一个更高层一些的自动代码生成工具使用?ASM?/p>



回页?/strong>


Java cL件概q?/span>

所?Java cLӞ是通常?javac ~译器生的 .class 文g。这些文件具有严格定义的格式。ؓ了更好的理解 ASMQ首先对 Java cL件格式作一点简单的介绍。Java 源文件经q?javac ~译器编译之后,会生成对应的二q制文gQ如下图所C)。每个合法的 Java cL仉具备_的定义,而正是这U精的定义Q才使得 Java 虚拟机得以正读取和解释所有的 Java cL件?/p>
?2. ASM – Javac 程
?2. ASM – Javac 程

Java cL件是 8 位字节的二进制流。数据项按顺序存储在 class 文g中,盔R的项之间没有间隔Q这使得 class 文g变得紧凑Q减存储空间。在 Java cL件中包含了许多大不同的,׃每一的l构都有严格规定Q这使得 class 文g能够从头到尾被顺利地解析。下面让我们来看一?Java cL件的内部l构Q以便对此有个大致的认识?/p>

例如Q一个最单的 Hello World E序Q?/p>
public class HelloWorld {   public static void main(String[] args) {    System.out.println("Hello world");   }  }  

l过 javac ~译后,得到的类文g大致是:


?3. ASM – Java cL?/strong>
?3. ASM – Java cL? src=

从上图中可以看到Q一?Java cL件大致可以归?10 个项Q?/p>

  • MagicQ?/strong>该项存放了一?Java cL件的数Qmagic numberQ和版本信息。一?Java cL件的?4 个字节被UCؓ它的数。每个正的 Java cL仉是以 0xCAFEBABE 开头的Q这样保证了 Java 虚拟很轻杄分L?Java 文g和非 Java 文g?
  • VersionQ?/strong>该项存放?Java cL件的版本信息Q它对于一?Java 文gh重要的意义。因?Java 技术一直在发展Q所以类文g的格式也处在不断变化之中。类文g的版本信息让虚拟机知道如何去dq处理该cL件?
  • Constant PoolQ?/strong>该项存放了类中各U文字字W串、类名、方法名和接口名U、final 变量以及对外部类的引用信息等帔R。虚拟机必须为每一个被装蝲的类l护一个常量池Q常量池中存储了相应cd所用到的所有类型、字D和Ҏ的符号引用,因此它在 Java 的动态链接中起到了核心的作用。常量池的大^均占C整个cd的 60% 左右?
  • Access_flagQ?/strong>该项指明了该文g中定义的是类q是接口Q一?class 文g中只能有一个类或接口)Q同时还指名了类或接口的讉K标志Q如 publicQprivate, abstract {信息?
  • This ClassQ?/strong>指向表示该类全限定名U的字符串常量的指针?
  • Super ClassQ?/strong>指向表示父类全限定名U的字符串常量的指针?
  • InterfacesQ?/strong>一个指针数l,存放了该cL父类实现的所有接口名U的字符串常量的指针。以上三Ҏ指向的常量,特别是前两项Q在我们?ASM 从已有类z新类时一般需要修改:类名称改ؓ子类名称Q将父类改ؓz前的cdUͼ如果有必要,增加新的实现接口?
  • FieldsQ?/strong>该项对类或接口中声明的字D进行了l致的描q。需要注意的是,fields 列表中仅列出了本cL接口中的字段Qƈ不包括从类和父接口l承而来的字Dc?
  • MethodsQ?/strong>该项对类或接口中声明的方法进行了l致的描q。例如方法的名称、参数和q回值类型等。需要注意的是,methods 列表里仅存放了本cL本接口中的方法,q不包括从超cd父接口承而来的方法。?ASM q行 AOP ~程Q通常是通过调整 Method 中的指o来实现的?
  • Class attributesQ?/strong>该项存放了在该文件中cL接口所定义的属性的基本信息?

事实上,使用 ASM 动态生成类Q不需要像早年?class hacker 一P熟知 class 文g的每一D,以及它们的功能、长度、偏U量以及~码方式。ASM 会给我们照顾好这一切的Q我们只要告?ASM 要改动什么就可以?—?当然Q我们首先得知道要改什么:对类文g格式了解的越多,我们p更好C?ASM q个利器?/p>



回页?/strong>


ASM 3.0 ~程框架

ASM 通过树这U数据结构来表示复杂的字节码l构Qƈ利用 Push 模型来对树进行遍历,在遍历过E中对字节码q行修改。所谓的 Push 模型cM于简单的 Visitor 设计模式Q因为需要处理字节码l构是固定的Q所以不需要专门抽象出一U?Vistable 接口Q而只需要提?Visitor 接口。所?Visitor 模式?Iterator 模式有点cMQ它们都被用来遍历一些复杂的数据l构。Visitor 相当于用h出的代表Q深入到法内部Q由法安排讉K行程。Visitor 代表可以更换Q但对算法流E无法干涉,因此是被动的Q这也是它和 Iterator 模式q户主动调遣算法方式的最大的区别?/p>

?ASM 中,提供了一?ClassReader c,q个cd以直接由字节数组或由 class 文g间接的获得字节码数据Q它能正的分析字节码,构徏出抽象的树在内存中表C字节码。它会调?accept ҎQ这个方法接受一个实C ClassVisitor 接口的对象实例作为参敎ͼ然后依次调用 ClassVisitor 接口的各个方法。字节码I间上的偏移被{换成 visit 事g旉上调用的先后Q所?visit 事g是指对各U不?visit 函数的调用,ClassReader 知道如何调用各种 visit 函数。在q个q程中用h法对操作q行q涉Q所以遍历的法是确定的Q用户可以做的是提供不同?Visitor 来对字节码树q行不同的修攏V?code>ClassVisitor 会生一些子q程Q比?visitMethod 会返回一个实?MethordVisitor 接口的实例,visitField 会返回一个实?FieldVisitor 接口的实例,完成子过E后控制q回到父q程Ql访问下一节点。因此对?ClassReader 来说Q其内部序讉K是有一定要求的。实际上用户q可以不通过 ClassReader c,自行手工控制q个程Q只要按照一定的序Q各?visit 事g被先后正的调用Q最后就能生成可以被正确加蝲的字节码。当然获得更大灵zL的同时也加大了调整字节码的复杂度?/p>

各个 ClassVisitor 通过职责?QChain-of-responsibilityQ?模式Q可以非常简单的装对字节码的各U修改,而无d注字节码的字节偏U,因ؓq些实现l节对于用户都被隐藏了,用户要做的只是覆写相应的 visit 函数?/p>

ClassAdaptor cdC ClassVisitor 接口所定义的所有函敎ͼ当新Z?ClassAdaptor 对象的时候,需要传入一个实C ClassVisitor 接口的对象,作ؓ职责链中的下一个访问?QVisitorQ,q些函数的默认实现就是简单的把调用委zq个对象Q然后依ơ传递下dŞ成职责链。当用户需要对字节码进行调整时Q只需?ClassAdaptor cL生出一个子c,覆写需要修改的ҎQ完成相应功能后再把调用传递下厅R这P用户无需考虑字节偏移Q就可以很方便的控制字节码?/p>

每个 ClassAdaptor cȝzcd以仅装单一功能Q比如删除某函数、修改字D可见性等{,然后再加入到职责链中Q这栯合更小Q重用的概率也更大,但代h产生很多对象,而且职责铄层次太长的话也会加大pȝ调用的开销Q用户需要在低耦合和高效率之间作出权衡。用户可以通过控制职责链中 visit 事g的过E,对类文gq行如下操作Q?/p>

  1. 删除cȝ字段、方法、指令:只需在职责链传递过E中中断委派Q不讉K相应?visit Ҏ卛_Q比如删除方法时只需直接q回 nullQ而不是返回由 visitMethod Ҏq回?MethodVisitor 对象?/p>
    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);   }  }           

  2. 修改cR字Dc方法的名字或修饰符Q在职责链传递过E中替换调用参数?/p>
    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);      }  }           

  3. 增加新的cR方法、字D?/p>

ASM 的最l的目的是生成可以被正常装蝲?class 文gQ因此其框架l构为客h供了一个生成字节码的工L —?ClassWriter。它实现?ClassVisitor 接口Q而且含有一?toByteArray() 函数Q返回生成的字节码的字节,字节流写回文g卛_生调整后的 class 文g。一般它都作责链的终点,把所?visit 事g的先后调用(旉上的先后Q,最l{换成字节码的位置的调_I间上的前后Q,如下例:

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);           

lg所qͼASM 的时序图如下Q?/p>
?4. ASM – 时序?/strong>
?4. ASM – 时序? src=




回页?/strong>


使用 ASM3.0 q行 AOP ~程

我们q是用上面的例子Q给 Account cd?security check 的功能。与 proxy ~程不同QASM 不需要将 Account 声明成接口,Account 可以仍旧是一个实现类。ASM 直接在 Account cM动手术,l?Accountoperation Ҏ首部加上?SecurityChecker.checkSecurity 的调用?/p>

首先Q我们将?ClassAdapter l承一个类?code>ClassAdapter ?ASM 框架提供的一个默认类Q负责沟?ClassReader ?ClassWriter。如果想要改?ClassReader 处读入的c,然后?ClassWriter 处输出,可以重写相应?ClassAdapter 函数。这里,Z改变 Accountoperation ҎQ我们将重写 visitMethdod Ҏ?/p>
class AddSecurityCheckClassAdapter extends ClassAdapter{     public AddSecurityCheckClassAdapter(ClassVisitor cv) {    //Responsechain 的下一?ClassVisitorQ这里我们将传入 ClassWriterQ?   //负责改写后代码的输出    super(cv);   }      //重写 visitMethodQ访问到 "operation" ҎӞ   //l出自定?MethodVisitorQ实际改写方法内?  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")) {       //使用自定?MethodVisitorQ实际改写方法内?     wrappedMv = new AddSecurityCheckMethodAdapter(mv);      }     }    return wrappedMv;   }  }     

下一步就是定义一个承自 MethodAdapter ?AddSecurityCheckMethodAdapterQ在“operation”Ҏ首部插入?SecurityChecker.checkSecurity() 的调用?/p>
class AddSecurityCheckMethodAdapter extends MethodAdapter {   public AddSecurityCheckMethodAdapter(MethodVisitor mv) {    super(mv);   }     public void visitCode() {    visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker",     "checkSecurity", "()V");   }  }      

其中Q?code>ClassReader d每个Ҏ的首部时调用 visitCode()Q在q个重写Ҏ里,我们?code>visitMethodInsn(Opcodes.INVOKESTATIC, "SecurityChecker","checkSecurity", "()V"); 插入了安全检查功能?/p>

最后,我们集成上面定义的 ClassAdapterQ?code>ClassReader?code>ClassWriter 产生修改后的 Account cL?

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();   }  }   

执行完这D늨序后Q我们会得到一个新?Account.class 文gQ如果我们用下面代码:

public class Main {   public static void main(String[] args) {    Account account = new Account();    account.operation();   }  }   

使用q个 AccountQ我们会得到下面的输出:

SecurityChecker.checkSecurity ...  operation...   

也就是说Q在 Account 原来?operation 内容执行之前Q进行了 SecurityChecker.checkSecurity() 查?/p>

动态生成类攚w成原始c?Account 的子c?/span>

上面l出的例子是直接攚w?Account cLw的Q从?Accountoperation Ҏ必须q行 checkSecurity 查。但事实上,我们有时仍希望保留原来的 Account c,因此把生成类定义为原始类的子cL更符?AOP 原则的做法。下面介l如何将攚w后的类定义?Account 的子c?Account$EnhancedByASM。其中主要有两项工作:

  • 改变 Class Description, 其命名?Account$EnhancedByASMQ将其父cL定ؓ Account?
  • 改变构造函敎ͼ其中对父类构造函数的调用转换为对 Account 构造函数的调用?

?AddSecurityCheckClassAdapter cMQ将重写 visit ҎQ?/p>
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";  //改变cd?  enhancedSuperName = name; //改变父类Q这里是”Account”   super.visit(version, access, enhancedName, signature,   enhancedSuperName, interfaces);  }   

改进 visitMethod ҎQ增加对构造函数的处理Q?/p>
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("<init>")) {     wrappedMv = new ChangeToChildConstructorMethodAdapter(mv,      enhancedSuperName);    }   }   return wrappedMv;  }   

q里 ChangeToChildConstructorMethodAdapter 负责把 Account 的构造函数改造成其子c?Account$EnhancedByASM 的构造函敎ͼ

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 && name.equals("<init>")) {      owner = superClassName;    }    super.visitMethodInsn(opcode, owner, name, desc);//改写父类为superClassName   }  }  

最后演CZ下如何在q行时生ƈ装入产生?Account$EnhancedByASM?我们定义一?Util c,作ؓ一个类工厂负责产生有安全检查的 Account c:

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());    }   }  }  

静态方?SecureAccountGenerator.generateSecureAccount() 在运行时动态生成一个加上了安全查的 Account 子类。著名的 Hibernate ?Spring 框架Q就是用这U技术实C AOP ?#8220;无损注入”?/p>



回页?/strong>


最后,我们比较一?ASM 和其他实?AOP 的底层技术:



lanxin1020 2009-05-12 12:43 发表评论
]]>
log4jQ{Q?/title><link>http://m.tkk7.com/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://m.tkk7.com/lanxin1020/archive/2009/05/04/268850.html</guid><wfw:comment>http://m.tkk7.com/lanxin1020/comments/268850.html</wfw:comment><comments>http://m.tkk7.com/lanxin1020/archive/2009/05/04/268850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/lanxin1020/comments/commentRss/268850.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/lanxin1020/services/trackbacks/268850.html</trackback:ping><description><![CDATA[<div id="nltrjlt" class="postbody clearfix"> <div style="position: relative" id="related_topics" _madepositioned="true">Log4J是Apache的一个开放源代码目(<a ><font color="#73af1d">http://logging.apache.org/log4j/docs/</font></a>)Q它是一个日志操作包。通过使用Log4J,可以指定日志信息输出的目的地Q控制每一条日志的输出格式Q定义日志信息的U别。所有这些功能通过一个配|文件灵z进行配|?</div> <p>一、LOG4Jl成</p> <p>    LOG4J主要׃大组件组成:<br />     . Logger: 军_什么日志信息应该被输出、什么日志信息应该被忽略Q?br />     . Appender: 指定日志信息应该输出C么地? q些地方可以是控制台、文件、网l设备;<br />     . Layout: 指定日志信息的输出格式;</p> <p>    一个Logger可以有多个AppenderQ也是说日志信息可以同时输出到多个讑֤上,每个Appender对应<br />     一ULayout(CZ见下??/p> <p>              ?nbsp; Appender1  →  Layout<br />      Q?nbsp;    <br />     Logger<br />      H? <br />               ?nbsp; Appender2  →  Layout</p> <p><br /> 二、Loggerlg</p> <p>    1. Loggerlg提供的方法:</p> <p>       Loggerlg是LOG4J的核心组Ӟ它代表了Log4J的日志记录器Q它能够Ҏ志信息进行分cȝ选。它由org.apache.log4j.Loggercd玎ͼ提供了如下方法:</p> <p> </p> <div id="lznbxzt" class="code_title">java 代码</div> <div id="bvhxfzp" class="dp-highlighter"> <div id="jtnrttj" class="bar"> <ol class="dp-j"> <li id="vnzbvnb" class="alt"><span><span id="hbtvzhf" class="keyword">package</span><span> org.apache.log4j;   </span></span> <li><span>  </span> <li id="bdfrxxn" class="alt"><span><span id="dtfzlrz" class="keyword">public</span><span> </span><span id="dlrvxnv" class="keyword">class</span><span> Logger {   </span> <li><span>  </span> <li id="nxrplrz" class="alt"><span>           </span><span id="hzbvxlb" class="comment">// Creation & retrieval methods: </span><span>  </span> <li><span>           </span><span id="tlxxbrh" class="keyword">public</span><span> </span><span id="ttfpjzh" class="keyword">static</span><span> Logger getRootLogger();   </span> <li id="zzjnpvt" class="alt"><span>           </span><span id="bbnxbxv" class="keyword">public</span><span> </span><span id="phrvxnd" class="keyword">static</span><span> Logger getLogger(String name);   </span> <li><span>  </span> <li id="hhlnpnl" class="alt"><span>           </span><span id="rrjvfnb" class="comment">// printing methods: </span><span>  </span> <li><span>           </span><span id="dnhbvlj" class="keyword">public</span><span> </span><span id="xxtnfnt" class="keyword">void</span><span> debug(Object message);   </span> <li id="nf9h7l9" class="alt"><span>           </span><span id="7n1pdrr" class="keyword">public</span><span> </span><span id="nf91zn1" class="keyword">void</span><span> info(Object message);   </span> <li><span>           </span><span id="r9hfzx9" class="keyword">public</span><span> </span><span id="p7dhrzj" class="keyword">void</span><span> warn(Object message);   </span> <li id="n7j91p9" class="alt"><span>           </span><span id="l79nhhj" class="keyword">public</span><span> </span><span id="hdv91z9" class="keyword">void</span><span> error(Object message);   </span> <li><span>           </span><span id="jdft1pp" class="keyword">public</span><span> </span><span id="bjlx9pz" class="keyword">void</span><span> fatal(Object message);   </span> <li id="rrdx7x9" class="alt"><span>      </span> <li><span>           </span><span id="99d9n9z" class="comment">// generic printing method: </span><span>  </span> <li id="7tv9j9h" class="alt"><span>           </span><span id="1bvxv91" class="keyword">public</span><span> </span><span id="zht7vdl" class="keyword">void</span><span> log(Priority p, Object message);   </span> <li><span>}   </span> </li> </ol> </div> <p>    2. 在配|文件中配置Loggerlg</p> <p>       可在Log4J配置文g中配|自qLoggerlgQ示例:</p> <p>       log4j.logger.myLogger=WARN</p> <p>       以上代码定义了一个LoggerlgQ名UCؓmyLoggerQ日志别ؓWARN?br />   <br />     3. 日志U别U类Q?/p> <p>       一共有五种Q别由高到低依ơ是Qfatal、error、warn、info、debug。获得Logger实例后,我们可调用以下方法之一输出日志信息Q?/p> <p>       public void debug(Object message);          //输出debugU别的日志信息;<br />        public void info(Object message);           //输出infoU别的日志信息;<br />        public void warn(Object message);           //输出warnU别的日志信息;<br />        public void error(Object message);          //输出errorU别的日志信息;<br />        public void fatal(Object message);          //输出fatalU别的日志信息;<br />        public void log(Priority p, Object message);//输出参数Priority指定U别的日志信息;</p> <p>       以上Ҏ只有当它的别大于或{于Loggerlg配置的日志别时才调用。以前面我们配置的myLoggerZQ它的日志别ؓWARN, 那么在程序中Q它的warn()、error()、fatal()Ҏ会被执行。对于log()ҎQ只有当它的参数Priority指定的日志别大于或{于WARNӞ它才会被执行?/p> <p>    4. Z么需要对日志q行分Q?br />     <br />        在写E序的时候,Z调试E序Q我们会在很多出错的地方输出大量的日志信息。当E序调试完,不需要这些信息时Q将E序中这些输出日志信息代码删除吗Q这栯时费力,对于大型E序几乎不可行。通过Ҏ志分U,假如不想输出WARNU别的日志信息,则Loggerlg的别调高即可,省时省心?/p> <p>    5. Loggerlg的承?/p> <p>       Log4J提供了一个root LoggerQ它是所有Loggerlg?#8220;先”,它永q存在,且不能通过名字索或引用Q通过Logger.getRootLogger()Ҏ取得它。配|root Logger代码Q?/p> <p>       log4j.rootLogger=INFO,console</p> <p>       可在配置文g中方便地配置存在l承关系的LoggerlgQ凡是在W号“.”后面的组仉会成为在W号“.”前面的Loggerlg的子cR例如:</p> <p>       log4j.apache.myLogger=WARN<br />        log4j.apache.myLogger.mySonLogger=,file</p> <p>       以上代码? mySonLogger是myLogger的子cLoggerlg。Loggerlg的承关p:<br />        . 如果子类Loggerlg没有定义日志U别Q则承父cȝ日志U别;<br />        . 如果子类Loggerlg定义了日志别,׃会承父cȝ日志U别;<br />        . 黙认情况下,子类Loggerlg会承父cL有的AppenderQ把它们加入到自qAppener;<br />        . 如果把子cLoggerlg的additivity标志设ؓfalseQ那么它׃会承父cAppender。additivity标志 默认gؓfalseQ?/p> <p>       以上配置的三个Loggerl承关系CZ如图Q?br />      <br />        root Logger: 日志U别=INFO  appender清单=console<br />                             ↑<br />        myLogger: 日志U别=WARN appender清单=null<br />                             ↑<br />        mySonLogger: 日志U别=null appender清单=file </p> <p>       q三个Loggerlg实际日志U别和Appender如下表:</p> <p>       Loggerlg          日志U别          Appender清单<br />        root Logger         INFO              console<br />        myLogger            WARN              console(l承)<br />        mySonLogger         WARN(l承)        fileQconsole(l承)<br />        <br /> 三、Appenderlg</p> <p>    Appenderlg军_日志信息输出到什么地斏V支持以下目的地Q?br />     . 控制?Console);<br />     . 文g(File);<br />     . GUIlg(GUI component);<br />     . 套接口服务器(Remote socket server);<br />     . NT的事件记录器(NT Event Logger);<br />     . UNIX Syslog守护q程(Remote UNIX Syslog daemon);</p> <p>    一个Logger可同时对应多个AppenderQ示例:myLogger配置二个Appender: 一个file, 一个是consoleQ?/p> <p>    log4j.logger.myAppender=WARN,file,console</p> <p>    log4j.appender.file=org.apache.log4j.RollingFileAppender<br />     log4j.appender.file.File=log.txt</p> <p>    log4j.apender.console=org.apache.log4j.ConsoleAppender</p> <p>四、Layoutlg</p> <p>    Layoutlg军_日志输出格式Q有以下几种cdQ?br />     . org.apache.log4j.HTMLLayout(以HTML表格形式布局);<br />     . org.apache.log4j.PatternLayout(可以灉|地指定布局模式);<br />     . org.apache.log4j.SimpleLayout(包含日志信息的别和信息字符?;<br />     . org.apache.log4j.TTCCLayout(包含日志产生的时间、线E和cd{信?;<br />     <br />     为名UCؓconsole的Appender配置SimpleLayoutQ代码如下:</p> <p>    log4j.appender.console.layout=org.apache.log4j.SimpleLayout</p> <p>    输出日志格式如下Q?/p> <p>    WARN - This is a log message from the myLogger<br />     <br />     为名UCؓfile的Appender配置PatternLayoutQ代码如下:</p> <p>    log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />     log4j.appender.file.layout.ConversionPattern=%t %p - %m%n</p> <p>    输出日志格式如下Q?/p> <p>    THREAD-1 WARN - This is a log message from the myLogger</p> <p>    PatternLayout让开发者依照ConversionPattern定义输出格式。ConversionPattern中一些指定日志内容和格式的预定义W号说明如下Q?/p> <p>    W号         描述<br />     %r           自程序开始后消耗的毫秒?br />     %t           表示日志记录h生成的线E?br />     %p           表示日专语句的优先<br />     %r           与日志请求相关的cd名称<br />     %c           日志信息所在的cd<br />     %m%n         表示日志信息的内?/p> <p>五、Log4J的基本用?/p> <p>    1. 定义配置文g<br />        Log4J支持二种配置文g格式QXML和Java属性文?采用“??#8221;形式)。以下ؓJava属性文?br />        格式配置文gQ?br />       <br />        . 配置Loggerlg<br />          <br />          配置root Logger语法为:log4j.rootLogger=[priority],appenderName,appenderName,...<br />          配置自定义Loggerlg语法为:log4j.logger.loggerName=[priority],appenderName,appenderName,...</p> <p>         其中Qpriority为日志别,可选值包括FATAL、ERROR、WARN、INFO、DEBUG、ALLQ?br />                appenderName指定AppenderlgQ可指定多个;         </p> <p>       . 配置Appenderlg</p> <p>         配置日志信息输出目的地Appender, 语法为:<br />          log4j.appender.appenderName=fully.ualified.name.of.appender.class<br />          log4j.appender.appenderName.option1=value1<br />          ...<br />          log4j.appender.appenderName.optionN=valueN</p> <p>         Log4J提供的Appender有以下几U:</p> <p>         a. org.apache.log4j.ConsoleAppender(控制?;<br />          b. org.apache.log4j.FileAppender(文g);<br />          c. org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文?;<br />          d. org.apache.log4j.RollingFileAppender(文g大小到指定尺生一个新的文?;<br />          e. org.apache.log4j.WriteAppender(日志信息以格式发送到L指定地方);</p> <p>       . 配置Layoutlg</p> <p>         配置Layoutlg语法为:<br />          log4j.appender.appenderName.layout=fully.ualified.name.of.appender.class<br />          log4j.appender.appenderName.layout.option1=value1<br />          ...<br />          log4j.appender.appenderName.layout.optionN=valueN</p> <p>         下面Z配置文gCZQ文件名为log4j.propertiesQ?/p> <p>         ## LOGGERS ##</p> <p>         #configure root logger<br />          log4j.rootLogger=INFO,console<br />          #define a logger named myLogger<br />          log4j.logger.myLogger=WARN<br />          #define a second logger that is a child to myLogger<br />          log4j.logger.myLogger.mySonLogger=,file</p> <p>         ## APPENDERS ##</p> <p>         #define an appender named console, which is set to be a ConsoleAppender<br />          log4j.appender.console=org.apache.log4j.ConsoleAppender</p> <p>         # define an appender named file, which is set to be a RollingFileAppender<br />          log4j.appender.file=org.apache.log4j.FileAppender<br />          log4j.appender.file.File=log.txt</p> <p>         ## LAYOUTS ##<br />          # assian a SimpleLayout to console appender<br />          log4j.appender.console.layout=org.apache.log4j.SimpleLayout</p> <p>         # assian a PatternLayout to file appender<br />          log4j.appender.file.layout=org.apache.log4j.PatternLayout<br />          log4j.appender.file.layout.ConversionPattern=%t%p-%m%n<br />          <br />     2. E序中用Log4j</p> <p>       . 获得日志记录器:</p> <p>         获得rootLoggerQLogger rootLogger=Logger.getRootLogger();<br />          获得自定义LoggerQLogger myLogger = Logger.getLogger("log4j.logger.myLogger");</p> <p>       . d日志记录器,配置Log4J环境;</p> <p>         a. BasicConfigurator.configure(): 自动快速地使用默认Log4J环境;<br />          b. Property.configurator.configure(String configFilename): d使用Java属性格式的配置文gq|Log4J环境Q?br />          c. DOMConfigurator.configure(String filename): dXML形式的配|文件ƈ配置LOG4J环境;</p> <p>       . 输出日志信息;</p> <p>         在程序代码中需要生成日志的地方Q调用Logger的各U输出日志方法输Z同别的日志Q例如:<br />          <br />          myLogger.debug("Thie is a log message from the " + myLogger.getName());</p> <p>         下面Z使用Log4J的程序,E序名ؓTest.javaQ?/p> <div id="9xpl7rz" class="code_title">java 代码</div> <div id="7zz9j9h" class="dp-highlighter"> <div id="99plzlj" class="bar"> <ol class="dp-j"> <li id="dn9hljz" class="alt"><span><span> </span><span id="7911z79" class="keyword">import</span><span> org.apache.log4j.Logger;   </span></span> <li><span> </span><span id="pj7h9lt" class="keyword">import</span><span> org.apache.log4j.PropertyConfigurator;   </span> <li id="p9h1zh1" class="alt"><span>    </span> <li><span> </span><span id="b99hvbl" class="keyword">public</span><span> </span><span id="bx7fp7l" class="keyword">class</span><span> Test {   </span> <li id="1rp99hf" class="alt"><span>  </span> <li><span>   </span><span id="bz9199f" class="keyword">public</span><span> </span><span id="dfld799" class="keyword">static</span><span> </span><span id="197zbzx" class="keyword">void</span><span> main(String[] args) {   </span> <li id="pj9xrzp" class="alt"><span>     </span><span id="llhj7l9" class="comment">//Get an instance of the myLogger </span><span>  </span> <li><span>     Logger myLogger = Logger.getLogger(</span><span id="bd9rv99" class="string">"myLogger"</span><span>);   </span> <li id="79p7p99" class="alt"><span>      </span> <li><span>     </span><span id="711j9p9" class="comment">//Get an instance of the childLogger </span><span>  </span> <li id="xb9xbp9" class="alt"><span>     Logger mySonLogger = Logger.getLogger(</span><span id="7bnzxlb" class="string">"myLogger.mySonLogger"</span><span>);   </span> <li><span>     </span><span id="hr9p91l" class="comment">//Load the proerties using the PropertyConfigurator </span><span>  </span> <li id="vdbvr9d" class="alt"><span>     PropertyConfigurator.configure(</span><span id="1xzbhdb" class="string">"log4j.properties"</span><span>);   </span> <li><span>  </span> <li id="19d7ll9" class="alt"><span>     </span><span id="9bdxl19" class="comment">//Log Messages using the Parent Logger </span><span>  </span> <li><span>     myLogger.debug(</span><span id="zbprlbl" class="string">"Thie is a log message from the "</span><span> + myLogger.getName());   </span> <li id="brp77fd" class="alt"><span>     myLogger.info(</span><span id="rjxhrr1" class="string">"Thie is a log message from the "</span><span> + myLogger.getName());   </span> <li><span>     myLogger.warn(</span><span id="fph7ddx" class="string">"Thie is a log message from the "</span><span> +  myLogger.getName());   </span> <li id="7v9zt9n" class="alt"><span>     myLogger.error(</span><span id="pzr79pp" class="string">"Thie is a log message from the "</span><span> + myLogger.getName());   </span> <li><span>     myLogger.fatal(</span><span id="fp99dl9" class="string">"Thie is a log message from the "</span><span> + myLogger.getName());   </span> <li id="jbdfh99" class="alt"><span>  </span> <li><span>     mySonLogger.debug(</span><span id="979t9r9" class="string">"Thie is a log message from the "</span><span> + mySonLogger.getName());   </span> <li id="t7drtjr" class="alt"><span>     mySonLogger.info(</span><span id="7lrb9rx" class="string">"Thie is a log message from the "</span><span> + mySonLogger.getName());   </span> <li><span>     mySonLogger.warn(</span><span id="1dvrbrf" class="string">"Thie is a log message from the "</span><span> +  mySonLogger.getName());   </span> <li id="hrt9hff" class="alt"><span>     mySonLogger.error(</span><span id="r9r91jh" class="string">"Thie is a log message from the "</span><span> + mySonLogger.getName());   </span> <li><span>     mySonLogger.fatal(</span><span id="7f9rrp9" class="string">"Thie is a log message from the "</span><span> + mySonLogger.getName());   </span> <li id="9pr9lpf" class="alt"><span>   }   </span> <li><span>}   </span> </li> </ol> </div> <p>        E序q行l果?</p> <p>        WARN - Thie is a log message from the myLogger<br />         ERROR - Thie is a log message from the myLogger<br />         FATAL - Thie is a log message from the myLogger<br />         WARN - Thie is a log message from the myLogger.mySonLogger<br />         ERROR - Thie is a log message from the myLogger.mySonLogger<br />         FATAL - Thie is a log message from the myLogger.mySonLogger</p> <p>        另在Test.class所在的目录下看C个log.txt文gQ内容如下:</p> <p>        WARN - Thie is a log message from the myLogger.mySonLogger<br />         ERROR - Thie is a log message from the myLogger.mySonLogger<br />         FATAL - Thie is a log message from the myLogger.mySonLogger</p> <p>        如将配置文glog4j.properties中语?/p> <p> log4j.logger.myLogger.mySonLogger=,file</p> <p> 改ؓ</p> <p> log4j.logger.myLogger.mySonLogger=,file,console</p> <p> 再次q行E序Q结果如下:</p> <p>        WARN - Thie is a log message from the myLogger<br />         ERROR - Thie is a log message from the myLogger<br />         FATAL - Thie is a log message from the myLogger<br />         WARN - Thie is a log message from the myLogger.mySonLogger<br />         WARN - Thie is a log message from the myLogger.mySonLogger<br />         ERROR - Thie is a log message from the myLogger.mySonLogger<br />         ERROR - Thie is a log message from the myLogger.mySonLogger<br />         FATAL - Thie is a log message from the myLogger.mySonLogger         <br />         FATAL - Thie is a log message from the myLogger.mySonLogger</p> <p>        mySonLogger的日志在控制C输出了二ơ,q是因ؓmySonLoggerl承了父cconsole AppenderQ?br />         本n又定义了一个console Appender, 因而有二个console Appender?/p> <p>六、在web应用中用Log4J</p> <p>    创徏一个ServletQ在它初始化Ҏ中读取Log4J配置文gq|Log4J环境Q这个Servlet在Web应用?br />     动时候被加蝲和初始化Q然后就可在其它Weblg中获取Logger对象q输出日志?/p> <p>    1. 创徏用于配置Log4J环境的Servlet</p> <div id="d7b7r9n" class="code_title">java 代码</div> <div id="nnr9t99" class="dp-highlighter"> <div id="v9lb9ff" class="bar"> <ol class="dp-j"> <li id="xfz79dt" class="alt"><span><span id="vv7hlzp" class="keyword">import</span><span> javax.servlet.*;   </span></span> <li><span><span id="vx1h977" class="keyword">import</span><span> javax.servlet.http.*;   </span> <li id="blnlvb9" class="alt"><span><span id="v9tprpf" class="keyword">import</span><span> java.io.*;   </span> <li><span><span id="zptl9b9" class="keyword">import</span><span> java.util.*;   </span> <li id="hjd9d97" class="alt"><span>  </span> <li><span><span id="prl79pp" class="keyword">import</span><span> org.apache.log4j.PropertyConfigurator;   </span> <li id="71v1hhp" class="alt"><span>  </span> <li><span><span id="jlfl99z" class="keyword">public</span><span> </span><span id="xh7bdtr" class="keyword">class</span><span> Log4JServlet </span><span id="dlfr9fx" class="keyword">extends</span><span> HttpServlet {   </span> <li id="799xz9v" class="alt"><span>      </span><span id="p9vt9rp" class="keyword">public</span><span> </span><span id="79djx99" class="keyword">void</span><span> init() </span><span id="xp99j99" class="keyword">throws</span><span> ServletException {   </span> <li><span>           String path = getServletContext().getRealPath(</span><span id="x9xlfb9" class="string">"/"</span><span>);   </span> <li id="h1p999b" class="alt"><span>           </span><span id="lfhb7hf" class="comment">//getInitParameter("propfile")Ҏ从web.xml文g中读取Log4J配置文g的名?profile"?</span><span>  </span> <li><span>           String propfile = path + getInitParameter(</span><span id="xhrd9z9" class="string">"propfile"</span><span>);   </span> <li id="v7lz9t9" class="alt"><span>           PropertyConfigurator.configure(propfile);   </span> <li><span>      }   </span> <li id="z799nzb" class="alt"><span>}   </span> <li><span>  </span> </li> </ol> </div> <p>      该Servlet在web.xml中的配置如下Q?br /> </p> <div id="7d9fj9l" class="code_title">xml 代码</div> <div id="vnr9j9v" class="dp-highlighter"> <div id="7zjvj99" class="bar"> <ol class="dp-xml"> <li id="7tvpf9p" class="alt"><span><span id="x9vfzb9" class="tag"><</span><span id="nxrt7x1" class="tag-name">servlet</span><span id="799xphr" class="tag">></span><span>  </span></span> <li><span>  </span><span id="dl7hj9b" class="tag"><</span><span id="9hlvpfd" class="tag-name">servlet-name</span><span id="p9d9pxx" class="tag">></span><span>log4jServlet</span><span id="9llfhp9" class="tag"></</span><span id="nfxrtj9" class="tag-name">servlet-name</span><span id="v9t1ttr" class="tag">></span><span>  </span> <li id="j999zv9" class="alt"><span>  </span><span id="fz9jnlh" class="tag"><</span><span id="7n9rtp9" class="tag-name">servlet-class</span><span id="v99z9n9" class="tag">></span><span>Log4JServlet</span><span id="9btnpfd" class="tag"></</span><span id="vpjb7zj" class="tag-name">servlet-class</span><span id="d9zfjpn" class="tag">></span><span>  </span> <li><span>  </span><span id="j9h99nn" class="tag"><</span><span id="7bd9d99" class="tag-name">init-param</span><span id="ldxzbpp" class="tag">></span><span>  </span> <li id="799rvdr" class="alt"><span>    </span><span id="7xzbv9x" class="tag"><</span><span id="rtn79nd" class="tag-name">param-name</span><span id="lvhb9h9" class="tag">></span><span>propfile</span><span id="nn9bl9x" class="tag"></</span><span id="7h9ttlb" class="tag-name">param-name</span><span id="zj9bdb9" class="tag">></span><span>  </span> <li><span>    </span><span id="7r9dvd9" class="tag"><</span><span id="n919n9z" class="tag-name">param-value</span><span id="79fd9jx" class="tag">></span><span>/WEB-INF/log4j.properties</span><span id="b99prhr" class="tag"></</span><span id="vvzr9z9" class="tag-name">param-value</span><span id="hzbd999" class="tag">></span><span>  </span> <li id="99dx99f" class="alt"><span>  </span><span id="jvp7j9b" class="tag"></</span><span id="7zbx9zn" class="tag-name">init-param</span><span id="9ptxl9n" class="tag">></span><span>  </span> <li><span>  </span><span id="f7hj9tz" class="tag"><</span><span id="pp9jljt" class="tag-name">load-on-startup</span><span id="rl7vnnj" class="tag">></span><span>1</span><span id="jttnz9r" class="tag"></</span><span id="7t1v91p" class="tag-name">load-on-startup</span><span id="pjl1lvn" class="tag">></span><span>  </span> <li id="xxz9ttj" class="alt"><span><span id="rrvntzr" class="tag"></</span><span id="td7vh9b" class="tag-name">servlet</span><span id="t9bv71h" class="tag">></span><span>  </span> </li> </ol> </div> <p>2. 在login.jsp中输出日?br />        <<a href="mailto:%@page"><font color="#73af1d">%@page</font></a> import="org.apache.log4j.Logger"%><br />        <html><br />          <head><br />            <title>login</title><br />          </head><br />          <body><br />            <%<br />              Logger myLogger = Logger.getLogger("myLogger");<br />              Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");<br />              myLogger.debug("Thie is a log message from the " + myLogger.getName());<br />              myLogger.info("Thie is a log message from the " + myLogger.getName());<br />              myLogger.warn("Thie is a log message from the " +  myLogger.getName());<br />              myLogger.error("Thie is a log message from the " + myLogger.getName());<br />              myLogger.fatal("Thie is a log message from the " + myLogger.getName());</p> <p>             mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());<br />              mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());<br />              mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());<br />              mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());<br />              mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());<br />            %><br />            <br><br />              <form name="loginForm" method="post" action="dispatcher"><br />              username: <input type="text" name="username"><br />              <br><br />              password: <input type="text" name="password"><br />              <br><br />              <input type="submit" name="submit" value="submit"><br />            </form><br />          </body><br />        </html><br />                <br />     3. 发布q行使用Log4J的web应用<br />        1) Log4J的JAR文g拯至目录:<WEB应用所在目?gt;/WEB-INF/lib<br />        2) 创徏Log4J的配|文件log4j.properties, 存放目录为:<WEB应用所在目?gt;/WEB-INF。内容同前面配置文gCZ?br />        3) ~译Log4JServlet, 存放至目录: <WEB应用所在目?gt;/WEB-INF/classes<br />        4) 修改web.xml文gQ加入以下内容:<br /> </p> <div id="hxzvbxx" class="code_title">xml 代码</div> <div id="p9fxltr" class="dp-highlighter"> <div id="z7h99vt" class="bar"> <ol class="dp-xml"> <li id="jd7fhn9" class="alt"><span><span id="7rlnxvn" class="tag"><</span><span id="xpbtxl9" class="tag-name">servlet</span><span id="hzrlnvj" class="tag">></span><span>  </span></span> <li><span>  </span><span id="pz7lnbr" class="tag"><</span><span id="7txhbj9" class="tag-name">servlet-name</span><span id="l99h9vv" class="tag">></span><span>log4jServlet</span><span id="1zbvzpl" class="tag"></</span><span id="d19v19n" class="tag-name">servlet-name</span><span id="lb7nxvn" class="tag">></span><span>  </span> <li id="7pbtn91" class="alt"><span>  </span><span id="zt79999" class="tag"><</span><span id="x9v9rhf" class="tag-name">servlet-class</span><span id="79t11r9" class="tag">></span><span>Log4JServlet</span><span id="b9lnpfn" class="tag"></</span><span id="j7pj919" class="tag-name">servlet-class</span><span id="79htv9x" class="tag">></span><span>  </span> <li><span>  </span><span id="h9xj9pf" class="tag"><</span><span id="bdf799j" class="tag-name">init-param</span><span id="fprlndr" class="tag">></span><span>  </span> <li id="7nztn99" class="alt"><span>    </span><span id="fz99ntj" class="tag"><</span><span id="jl9t99d" class="tag-name">param-name</span><span id="79lfzfl" class="tag">></span><span>profile</span><span id="rrvxhh9" class="tag"></</span><span id="l9z99hv" class="tag-name">param-name</span><span id="799z9p9" class="tag">></span><span>  </span> <li><span>    </span><span id="rr7l99d" class="tag"><</span><span id="nhjdxl7" class="tag-name">param-value</span><span id="hprvfxv" class="tag">></span><span>/WEB-INF/log4j.properties</span><span id="fbnzl9d" class="tag"></</span><span id="r9pbltj" class="tag-name">param-value</span><span id="xpb9xp7" class="tag">></span><span>  </span> <li id="71tv9b9" class="alt"><span>  </span><span id="df7fvrh" class="tag"></</span><span id="zbv71br" class="tag-name">init-param</span><span id="ldn9d99" class="tag">></span><span>  </span> <li><span>  </span><span id="x7p9jf1" class="tag"><</span><span id="17bx9db" class="tag-name">load-on-startup</span><span id="jbvpzfn" class="tag">></span><span>1</span><span id="vvf9h99" class="tag"></</span><span id="b9zbd9p" class="tag-name">load-on-startup</span><span id="z99v999" class="tag">></span><span>  </span> <li id="79rt9rr" class="alt"><span><span id="x9pjb9l" class="tag"></</span><span id="t9r9lrh" class="tag-name">servlet</span><span id="p7dx79p" class="tag">></span><span>  </span> </li> </ol> </div> <p><br />        5) 启动服务器,讉Klogin.jsp面Q在服务器控制台上看到如下日志:<br />           WARN - Thie is a log message from the myLogger<br />           ERROR - Thie is a log message from the myLogger<br />           FATAL - Thie is a log message from the myLogger<br />           WARN - Thie is a log message from the myLogger.mySonLogger<br />           ERROR - Thie is a log message from the myLogger.mySonLogger<br />           FATAL - Thie is a log message from the myLogger.mySonLogger</p> <p>          另在<WEB应用所在目?gt;/WEB-INF目录下看C个log.txt文gQ内容如下:</p> <p>          WARN - Thie is a log message from the myLogger.mySonLogger<br />           ERROR - Thie is a log message from the myLogger.mySonLogger<br />           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://m.tkk7.com/lanxin1020/aggbug/268850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-04 17:19 <a href="http://m.tkk7.com/lanxin1020/archive/2009/05/04/268850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j(?http://m.tkk7.com/lanxin1020/archive/2009/05/04/268815.htmllanxin1020lanxin1020Mon, 04 May 2009 06:40:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/05/04/268815.htmlhttp://m.tkk7.com/lanxin1020/comments/268815.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/05/04/268815.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/268815.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/268815.html在实际编E时Q要?span class="hilite1">Log4j真正在系l中q行事先q要寚w|文件进行定义。定义步骤就是对Logger、Appender及Layout的分别用?br />   Log4j支持两种配置文g格式Q一U是XML格式的文Ӟ一U是java propertiesQkey=valueQ【JavaҎ文Ӟ?|】。下面我们介l用JavaҎ文件做为配|文件的Ҏ
  具体如下Q?br />   
  1、配|根Logger Q?/strong> 其语法ؓQ?br />   log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
  level : 是日志记录的优先U,分ؓOFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的别?span class="hilite1">Log4j只用四个别,优先U从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的U别Q您可以控制到应用程序中相应U别的日志信息的开兟뀂比如在q里?义了INFOU别Q则应用E序中所有DEBUGU别的日志信息将不被打印出来?br />   appenderName:是指定日志信息输出到哪个地斏V您可以同时指定多个输出目的地?br />   例如Q?span class="hilite1">log4j.rootLoggerQinfo,A1,B2,C3
  
  2、配|日志信息输出目的地 Q其语法为:
  log4j.appender.appenderName = fully.qualified.name.of.appender.class   //
     "fully.qualified.name.of.appender.class" 可以指定下面五个目的C的一个:
      1.org.apache.log4j.ConsoleAppenderQ控制台Q?br />       2.org.apache.log4j.FileAppenderQ文Ӟ
      3.org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ
      4.org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ
      5.org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)
        1.ConsoleAppender选项
              Threshold=WARN:指定日志消息的输出最低层ơ?br />               ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />               Target=System.errQ默认情况下是:System.out,指定输出控制?br />         2.FileAppender 选项
              Threshold=WARN:指定日志消息的输出最低层ơ?br />               ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />               File=mylog.txt:指定消息输出到mylog.txt文g?br />               Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />         3.DailyRollingFileAppender 选项
              Threshold=WARN:指定日志消息的输出最低层ơ?br />               ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />               File=mylog.txt:指定消息输出到mylog.txt文g?br />               Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />               DatePattern='.'yyyy-ww:每周滚动一ơ文Ӟx周生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:
              1)'.'yyyy-MM: 每月
              2)'.'yyyy-ww: 每周
              3)'.'yyyy-MM-dd: 每天
              4)'.'yyyy-MM-dd-a: 每天两次
              5)'.'yyyy-MM-dd-HH: 每小?br />               6)'.'yyyy-MM-dd-HH-mm: 每分?br />         4.RollingFileAppender 选项
              Threshold=WARN:指定日志消息的输出最低层ơ?br />               ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />               File=mylog.txt:指定消息输出到mylog.txt文g?br />               Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />               MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小Ӟ会自动滚动Q即原来的内容Udmylog.log.1文g?br />               MaxBackupIndex=2:指定可以产生的滚动文件的最大数?实际应用Q?br />   log4j.appender.A1=org.apache.log4j.ConsoleAppender //q里指定了日志输出的W一个位|A1是控制台ConsoleAppender
  
  3、配|日志信息的格式 Q?/span> 其语法ؓQ?br />   A. log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
          "fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个:
        1.org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
       2.org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
       3.org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
       4.org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)
            1.HTMLLayout 选项
              LocationInfo=true:默认值是false,输出java文g名称和行?br />               Title=my app file: 默认值是 Log4J Log Messages.
            2.PatternLayout 选项
              ConversionPattern=%m%n :指定怎样格式化指定的消息?br />             3.XMLLayout   选项
              LocationInfo=true:默认值是false,输出java文g和行?br />   实际应用Q?br />     log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    B . log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
        q里需要说明的是日志信息格式中几个符h代表的含义:
         QX? X信息输出时左寚wQ?br />             %p: 输出日志信息优先U,即DEBUGQINFOQWARNQERRORQFATAL,
            %d: 输出日志旉点的日期或时_默认格式为ISO8601Q也可以在其后指定格式,比如Q?d{yyy MMM dd HH:mm:ss,SSS}Q输出类|2002q?0?8?22Q?0Q?8Q?21
            %r: 输出自应用启动到输出该log信息耗费的毫U数
            %c: 输出日志信息所属的cȝQ通常是所在类的全?br />             %t: 输出产生该日志事件的U程?br />             %l: 输出日志事g的发生位|,相当?C.%M(%F:%L)的组?包括cȝ名、发生的U程Q以及在代码中的行数。D例:Testlog4.main(TestLog4.java:10)
            %x: 输出和当前线E相兌的NDC(嵌套诊断环境),其用到像java servletsq样的多客户多线E的应用中?br />             %%: 输出一?%"字符
            %F: 输出日志消息产生时所在的文g名称
            %L: 输出代码中的行号
            %m: 输出代码中指定的消息,产生的日志具体信?br />             %n: 输出一个回车换行符QWindowsq_?\r\n"QUnixq_?\n"输出日志信息换行
        可以?与模式字W之间加上修饰符来控制其最宽度、最大宽度、和文本的对齐方式。如Q?br />               1)%20cQ指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q默认的情况下右寚w?br />               2)%-20c:指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q?-"h定左寚w?br />               3)%.30c:指定输出category的名Uͼ最大的宽度?0Q如果category的名U大?0的话Q就会将左边多出的字W截掉,但小?0的话也不会有I格?br />               4)%20.30c:如果category的名U小?0pI格Qƈ且右寚wQ如果其名称长于30字符Q就从左边交q销出的字符截掉?br />   q里上面三个步骤是对前面Log4jlg说明的一个简化;下面l出一个具体配|例子,在程序中可以参照执行Q?br />   log4j.rootLogger=INFO,A1QB2
  log4j.appender.A1=org.apache.log4j.ConsoleAppender
  log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
  Ҏ上面的日志格式,某一个程序的输出l果如下Q?br />   0  INFO 2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with log4j, Fri Jun 13 13:23:46 CST 2003'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT

  4. # 当输Z息于回滚文g?/span>
      log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender   //指定以文件的方式输出日志
        log4j.appender.ROLLING_FILE.Threshold=ERROR
        log4j.appender.ROLLING_FILE.File=rolling.log   //文g位置,也可以用变量${java.home}、rolling.log
        log4j.appender.ROLLING_FILE.Append=true
        log4j.appender.ROLLING_FILE.MaxFileSize=10KB   //文g最大尺?br />         log4j.appender.ROLLING_FILE.MaxBackupIndex=1   //备䆾?br />         log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
        log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n     
××××××××××××××××××××××××××××××××××××××××××××××××

附:Log4j比较全面的配|?/span>
LOG4J的配|之单它遍及于来多的应用中了:Log4J配置文g实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签{全套功能。择其一二用就够用了,
log4j.rootLogger=DEBUG,CONSOLE,A1,im
log4j.addivity.org.apache=true
# 应用于控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.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
#应用于文?
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis
# 应用于文件回?
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log   //文g位置,也可以用变量${java.home}、rolling.log
log4j.appender.ROLLING_FILE.Append=true     //true:d   false:覆盖
log4j.appender.ROLLING_FILE.MaxFileSize=10KB   //文g最大尺?br /> log4j.appender.ROLLING_FILE.MaxBackupIndex=1   //备䆾?br /> log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

#应用于socket
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.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

# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志给邮g
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=web@www.wuset.com
log4j.appender.MAIL.SMTPHost=www.wusetu.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=web@www.wusetu.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# 用于数据?
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
#自定义Appender
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@cybercorlin.net
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n



lanxin1020 2009-05-04 14:40 发表评论
]]>
log4j(?http://m.tkk7.com/lanxin1020/archive/2009/05/04/268813.htmllanxin1020lanxin1020Mon, 04 May 2009 06:37:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/05/04/268813.htmlhttp://m.tkk7.com/lanxin1020/comments/268813.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/05/04/268813.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/268813.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/268813.htmlLog4j下蝲
在apache|站Qjakarta.apache.org/log4j 可以免费下蝲?span class="hilite1">Log4j最新版本的软g包?

Log4j使用
Log4j的包下蝲完成后,解压Q将其中打包好的?span class="hilite1">log4j-1.x.x.jar导入你的工程LIB中?
Log4j之所以受Ƣ迎的原因之一是它的灵zL?span class="hilite1">Log4j提供了灵zȝ配置ҎQ默认是调用BasicConfigurator.configure()来进行配|,但如果只是简单的调用BasicConfigurator.configure()来进行配|工作,那么所有的配置都是固定的,不方便以后修攚w|。另一U是动态配|,Log4j提供了PropertyConfigurator.configure(……)来动态配|,参数可以是一个properties文g所在\径的String对象Q可以是一个properties文g所在\径的URL对象Q也可以是一个properties对象。如果要用XML文g来配|信息,则可用类型的DOMConfigurator()函数来从一个XML文g中加载配|信息。这U方式更方便修改配置?

动态配|?

Java代码
  1. package http;       
  2.       
  3. import org.apache.log4j.BasicConfigurator;       
  4. import org.apache.log4j.Logger;       
  5. import org.apache.log4j.PropertyConfigurator;       
  6. import org.apache.log4j.xml.DOMConfigurator;       
  7.       
  8. public class Log4jDemo {       
  9.     static Logger log = Logger.getLogger(Log4jDemo.class.getClass());       
  10.     /**     
  11.      * main     
  12.      * @param args     
  13.      */      
  14.     public static void main(String[] args) {       
  15.         BasicConfigurator.configure();//默认配置       
  16.         PropertyConfigurator.configure("c:/log4j.properties");       
  17.         //动态配|?参数可以是一个properties文g所在\径的String对象       
  18.         //可以是一个properties文g所在\径的URL对象Q也可以是一个properties对象       
  19.                
  20.         DOMConfigurator.configure("c:/log4j.xml");//XML配置文g       
  21.       
  22.         //PropertyConfigurator.configure()的参数还可以是XML、Properties对象       
  23.                
  24.         //下面可使用log4j       
  25.         log.info("info");       
  26.         log.debug("debug");       
  27.         log.error("error");       
  28.         log.warn("warn");       
  29.     }       
  30.       
  31. }      


J2EE应用log4j
上面代码描述?span class="hilite1">Log4j的简单应用,其实使用Log4j也就是这L单方ѝ当焉了上面的配置ҎQ还有其它,比如做一个J2EE应用Q在J2EE应用使用Log4jQ必d在启动服务时加蝲Log4j的配|文件进行初始化Q可以在web.xml中进行?


java 代码
Java代码
  1. import java.io.IOException;       
  2. import java.io.PrintWriter;       
  3.       
  4. import javax.servlet.ServletException;       
  5. import javax.servlet.http.HttpServlet;       
  6. import javax.servlet.http.HttpServletRequest;       
  7. import javax.servlet.http.HttpServletResponse;       
  8.       
  9.       
  10.       
  11. public class J2eeLog4jDemo extends HttpServlet {       
  12.       
  13.     public void destroy() {       
  14.         super.destroy();        
  15.     }          
  16.     public void doGet(HttpServletRequest request, HttpServletResponse response)       
  17.             throws ServletException, IOException {       
  18.     }       
  19.     public void doPost(HttpServletRequest request, HttpServletResponse response)       
  20.             throws ServletException, IOException {             
  21.     }       
  22.     public void init() throws ServletException {       
  23.         //通过web.xml来动态取得配|文?nbsp;      
  24.         String prefix = getServletContext().getRealPath("/");       
  25.         String file = getInitParameter("log4j");       
  26.       
  27.         //如果没有l出相应的配|文Ӟ则不q行初始?nbsp;      
  28.         if(file != null)        
  29.         {       
  30.             PropertyConfigurator.configure(prefix+file);       
  31.         }       
  32.     }       
  33.       
  34. }      

Web.xml 代码
Java代码
  1. <servlet>      
  2. <servlet-name>j2eelog4jdemoservlet-name>      
  3. <servlet-class>J2eeLog4jDemoservlet-class>      
  4. <init-param>      
  5. <param-name>log4jparam-name>      
  6. <param-value>log4j.propertiesparam-value>      
  7. init-param>      
  8. <load-on-startup>1load-on-startup>  //设ؓ1ӞWeb容器启动卌行加?nbsp;   
  9. servlet  


Spring配置Log4j
Spring中配|?span class="hilite1">Log4j只要配置applicationContext.xml文gQ?span class="hilite1">Log4j的配|文件放在Web工程的根目录下,默认是objectname/root?可以在web.xml中设|工E根目录.

讄根目?


web.xml 代码
Java代码
  1. <!--不定义webAppRootKey参数QwebAppRootKey是~省?/span>"webapp.root"-->      
  2.  <context-param>      
  3.   <param-name>webAppRootKeyparam-name>      
  4.   <param-value>webapp.rootparam-value>      
  5.  context-param>  


配置applicationContext.xml


applicationContext.xml 代码
Java代码
  1. <!--由Sprng载入?span class="hilite1">Log4j配置文g位置-->      
  2. <context-param>      
  3.  <param-name>log4jConfigLocationparam-name>      
  4.  <param-value>/WEB-INF/log4j.propertiesparam-value>      
  5.  <!--在这里定位配|文Ӟ需要的是从root开始的l对路径-->      
  6. context-param>      
  7.       
  8.       
  9.       
  10. <!--Spring默认hLog4j配置文g的间?单位为millisecond-->      
  11. <context-param>      
  12.  <param-name>log4jRefreshIntervalparam-name>      
  13.  <param-value>60000param-value>      
  14. context-param>      
  15.       
  16. <!--Spring log4j 监听?->      
  17. <listener>      
  18.  <listener-class>org.springframework.web.util.Log4jConfigListenerlistener-class>      
  19. listener>     


同时使用commons-logging?span class="hilite1">Log4j


1)首先在classpath下寻找自q配置文gcommons-logging.propertiesQ如果找刎ͼ则用其中定义的Log实现c?
2)如果找不到commons-logging.properties文gQ则在查找是否已定义pȝ环境变量org.apache.commons.logging.LogQ找到则使用其定义的Log实现c?
3)否则Q查看classpath中是否有Log4j的包Q如果发玎ͼ则自动?span class="hilite1">Log4j作ؓ日志实现c?
4)否则Q用JDK自n的日志实现类QJDK1.4以后才有日志实现c)
5)否则Q用commons-logging自己提供的一个简单的日志实现cSimpleLog


commons-logging?span class="hilite1">Log4j的jar包都攄到classpath下,同时也将Log4j的配|文件放到classpath中,两者就可以很好的合?实现如下Q?
Java代码
  1. package com.doctorcom.model;       
  2.       
  3. import org.apache.commons.logging.Log;       
  4.       
  5. public class LogFactorySupport {           
  6.           
  7.     public Log getLog(){       
  8.         Log log = org.apache.commons.logging.LogFactory.getLog(LogFactorySupport.class);       
  9.         log.info("");       
  10.         log.debug("");       
  11.     }       
  12.            
  13. }   


java 代码

Log4j配置内容
看一个简单的java属性配|文?span class="hilite1">log4j.propertiesQ?

properties 代码
Java代码
  1. #指定根LoggerQ及日志输出U别Q大于等于该U别的日志将被输出( DEBUG < INFO < WARN < ERROR < FATAL Q?nbsp;设ؓOFF可以关闭日志       
  2. log4j.rootLogger=DEBUG, A1,A2       
  3. #指定log输出目的,q里设ؓ输出日志到指定目录的文gmy.log?nbsp;      
  4. log4j.appender.A1=org.apache.log4j.FileAppender       
  5. log4j.appender.A1.File=\\logs\\my.log   #当前根目录下    
  6. #指定日志信息的格?nbsp;      
  7. log4j.appender.A1.layout=org.apache.log4j.PatternLayout        
  8. log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n       
  9.       
  10. #把A2输出到控制台       
  11. log4j.appender.A2=org.apache.log4j.ConsoleAppender       
  12. log4j.appender.A2.layout=org.apache.log4j.SimpleLayout        
  13.       
  14. #q可以单独指定输出某个包的日志?nbsp;      
  15. #log4j.logger.com.study.HelloLog4j=INFO   


1、配|根LoggerQ其语法为:
log4j.rootLogger = [ level ] , appenderName, appenderName2
levelQ日志的U别Q指定这条日志信息的重要性。分为ALL < DEBUG < INFO < WARN <error fatal=""></error>一般常用的?DEBUG Q?INFO QWARN QERROR四种Q分别对应Loggercȝ四种Ҏ
debug(Object message ) ;
info(Object message ) ;
warn(Object message ) ;
error(Object message ) ;
如果讄U别为INFOQ则优先U大于等于INFOU别Q如QINFO、WARN、ERRORQ的日志信息可以被输出,于该别的如:DEBUG不会被输出
appenderName :是指定日志信息输出目的圎ͼ比如Q打印到控制収ͼ输出到文件等Q。同一条日志信息可以配|多个输出目的地?

2、配|log输出目的?
Log4j提供以下几种Q?
org.apache.log4j.ConsoleAppenderQ控制台Q?
org.apache.log4j.FileAppenderQ文Ӟ
org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ
org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ
org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)
3、log信息的格?
org.apache.log4j.HTMLLayoutQHTML表格形式Q?
org.apache.log4j.SimpleLayoutQ简单格式的日志Q只包括日志信息的别和指定的信息字W串 Q如:DEBUG - HelloQ?
org.apache.log4j.TTCCLayoutQ日志的格式包括日志产生的时间、线E、类别等{信息)
org.apache.log4j.PatternLayoutQ灵zd自定义日志格式)

当用org.apache.log4j.PatternLayout来自定义信息格式Ӟ可以使用
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p -%m%n 来格式化信息
%c    输出所属类的全名,可写?%c{Num} ,Numcd输出的范?nbsp; 如:"com.sun.aaa.classB", %C{2}日志输出输出范围为:aaa.classB
%d    输出日志旉其格式ؓ 可指定格??%d{HH:mm:ss}{?
%l    输出日志事g发生位置Q包括类目名、发生线E,在代码中的行?
%n    换行W?
%m    输出代码指定信息Q如info(“message”),输出message
%p    输出日志的优先Q即 FATAL ,ERROR {?
%r    输出从启动到昄该条日志信息所耗费的时_毫秒敎ͼ
%t    输出产生该日志事件的U程?


lanxin1020 2009-05-04 14:37 发表评论
]]>
վ֩ģ壺 һ͵| Ѿþþþþ| ɫƷƵ| ձĻѿ| AVר4SE| 7723ձ| ؼaa**ëƬѹۿ| þþƷ77777| һƵѿ| þ99Ʒѿ| Ʒۺ| ޾ƷƵ| ȫëƬ| һ߹ۿ| һþAþѾƷ| ޿һ24鶹| þֹƷۺ| ŮվɫƵ| ޾ƷƵ| žAV뾫ƷëƬ| avպav| ޸Ļַ| aѹۿվ| yyһëƬƵ| ŷŷɫ| ٸĻӰ| ޾ƷƵ߹ۿ㶮| 18Ʒ׽߹ۿ| aëƬȫƵ18| 99޾Ʒ242| ղ2021| ޾Ʒþþþþþþþþþ| ѵһƬվ| 4huĻѵַ| ëƬ߹ۿ| ƷϵƵ| ŷۺһ| һ245699| AVɫ㽶һ| һŮ| ޾Ʒ߹ۿ |