从一个输出日志的实例分析Java的代理机制

转载 2007年09月20日 11:29:00
                                        通用的日志输出方法
在笔者使用Spring以前开发的程序中,不管是使用Java自动的日志工具,还是使用Log4j,或是自己编写的日志工具,都要在每一个业务逻辑方法里编写记录日志的代码。使用AOP就可以使业务逻辑和记录日志这两件事情分离开。这个输出日志实例的实现思路是:首先给出原来在程序中编写日志的方法,然后编写测试程序,查看输出结果,最后对这种方法进行总结,指出这种方法的缺点。具体编写步骤如下:
(1)打开Eclipse,在com.gc.action包中建立一个Java文件TimeBook.java,用来模拟实际业务中考勤审核的业务逻辑。
(2)原来在程序中编写日志时,都要在每一个业务逻辑方法里编写记录日志的代码。TimeBook.java的示例代码如下:
//******* TimeBook.java**************
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
public class TimeBook {
         private Logger logger = Logger.getLogger(this.getClass().getName());
         //审核数据的相关程序
         public void doAuditing(String name) {
                  logger.log(Level.INFO, name + " 开始审核数据....");
                  //审核数据的相关程序
                  ……   
                  logger.log(Level.INFO, name + " 审核数据结束....");
         }
}
代码说明:
  ●       在业务逻辑中使用log4j作为日志输出的工具。
  ●       doAuditing()方法用来处理实际业务中的考勤审核。
  ●       参数name,用来传入是谁执行了类TimeBook中的doAuditing()方法。
  ●       在审核代码的前后添加了用logger.log()方法实现日志输出的功能。
(3)编写测试程序,继续在以前的测试程序TestHelloWorld的基础上进行修改,TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
public class TestHelloWorld {
         public static void main(String[] args) {
                   TimeBook timeBook = new TimeBook();
timeBook.doAuditing("张三");
    }
}
代码说明:timeBook.doAuditing("张三")表示该程序的执行人是“张三”。
(4)运行测试程序,查看通过TimeBook类输出的日志信息,如图5.1所示。
图5.1  通过TimeBook类输出日志信息
在上面的示例中,笔者把日志信息添加在了具体的业务逻辑中,假如程序中其他的代码都需要日志输出的功能,那么每个程序就都要添加和上面类似的代码。这样,在程序中,就会存在很多类似的日志输出代码,造成了很大的耦合,通过什么方法可以使业务逻辑和输出日志的代码分离呢?通过面向接口编程可以改进这个问题。
   通过面向接口编程实现日志输出
通过前面的示例程序,读者可以了解到以前添加日志信息方法的缺点。下面主要通过面向接口编程来改进这个缺点。其实现思路是:首先把执行考勤审核的doAuditing()方法提取出来成为接口,然后通过一个实体类来实现这个方法,在这个方法里编写具体的考勤审核的业务逻辑,接着通过一个代理类来进行日志输出,最后编写测试程序,查看输出结果。具体步骤如下:
(1)在com.gc.impl包中,建立一个接口TimeBookInterface。TimeBookInterface.java的示例代码如下:
//******* TimeBookInterface.java**************
package com.gc.impl;
import org.apache.log4j.Level;
//通过面向接口编程实现日志输出
public interface TimeBookInterface {
         public void doAuditing(String name);
}
(2)在com.gc.action包中,使前面已经建立好的类TimeBook实现接口TimeBookInterface,在doAuditing()方法中编写具体的考勤审核代码。TimeBook.java的示例代码如下:
//******* TimeBook.java**************
package com.gc.action;
import com.gc.impl.TimeBookInterface;
public class TimeBook implements TimeBookInterface {
public void doAuditing(String name) {
//审核数据的相关程序
……   
}
}
(3)编写一个代理类,用来实现日志的输出,在该类中针对前面的接口TimeBookInterface编程,而不针对具体的类,从而实现具体业务逻辑与日志输出代码。TimeBookProxy.java的示例代码如下:
//******* TimeBookProxy.java**************
package com.gc.action;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.gc.impl.TimeBookInterface;
public class TimeBookProxy {
private Logger logger = Logger.getLogger(this.getClass().getName());
private TimeBookInterface timeBookInterface;
     //在该类中针对前面的接口TimeBookInterface编程,而不针对具体的类
     public TimeBookProxy(TimeBookInterface timeBookInterface) {
        this.timeBookInterface = timeBookInterface;
     }
          //实际业务处理
          public void doAuditing(String name) {
                   logger.log(Level.INFO, name + " 开始审核数据....");
                   timeBookInterface.doAuditing(name);   
                   logger.log(Level.INFO, name + " 审核数据结束....");
          }
}
(4)修改测试程序TestHelloWorld,把类TimeBook当作参数传入代理类TimeBookProxy中,从而实现对具体负责考勤审核类TimeBook的调用。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
public class TestHelloWorld {
         public static void main(String[ ] args) {
           //这里针对接口进行编程
TimeBookProxy timeBookProxy  = new TimeBookProxy(new TimeBook());
timeBookProxy .doAuditing("张三");
    }
}
(5)运行测试程序,可以得到通过TimeBookProxy类输出日志信息,如图5.2所示。
图5.2  通过TimeBookProxy类输出日志信息
和前面一个日志输出做对比,可以看到,在这个示例中,具体负责考勤审核的业务逻辑代码和日志信息的代码分离开了,并且以后只要实现了接口TimeBookInterface的类,都可以通过代理类TimeBookProxy实现日志信息的输出,而不用再每个类里面都写日志信息输出的代码,从而实现了日志信息的代码重用。
   使用Java的代理机制进行日志输出
前面的代码虽然有了一些改进,但是仍然有一定局限性,因为要使用代理类,就必须要实现固定的接口,有没有一种通用的机制,不管是不是实现这个接口,都可以实现日志信息的输出呢?
Java提供的InvocationHandler接口可以实现这种功能,首先编写一个日志信息的代理类,这个代理类实现了接口InvocationHandler,然后和前面一个实例类似,编写一个接口,并实现这个接口,在实现类中编写具体的考勤审核代码,最后针对接口编写测试类,查看测试结果。具体步骤如下:
(1)编写一个日志信息的代理类LogProxy,这个代理类实现了接口InvocationHandler,可以对任何接口实现日志信息的输出。LogProxy.java的示例代码如下:
//******* LogProxy.java**************
package com.gc.action;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
//代理类实现了接口InvocationHandler
public class LogProxy implements InvocationHandler {
         private Logger logger = Logger.getLogger(this.getClass().getName());
    private Object delegate;
    //绑定代理对象
    public Object bind(Object delegate) {
        this.delegate = delegate;
        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().
getInterfaces(), this);
    }
    //针对接口编程
    public Object invoke(Object proxy, Method method, Object[ ] args) throws Throwable {
        Object result = null;
        try {
                            //在方法调用前后进行日志输出
logger.log(Level.INFO, args[0] + " 开始审核数据....");
              result = method.invoke(delegate, args);
                            logger.log(Level.INFO, args[0] + " 审核数据结束....");
        } catch (Exception e){
            logger.log(Level.INFO, e.toString());
        }
        return result;
    }
}
(2)使用com.gc.impl包中的接口TimeBookInterface。TimeBookInterface.java的示例代码如下:
//******* TimeBookInterface.java**************
package com.gc.impl;
import org.apache.log4j.Level;
//针对接口编程
public interface TimeBookInterface {
         public void doAuditing(String name);
}
(3)使用com.gc.action包中的类TimeBook,doAuditing()方法中编写具体的考勤审核代码。TimeBook.java的示例代码如下:
//******* TimeBook.java**************
package com.gc.action;
import com.gc.impl.TimeBookInterface;
public class TimeBook implements TimeBookInterface {
public void doAuditing(String name) {
//审核数据的相关程序
……   
}
}
(4)修改测试代码TestHelloWorld,使用日志代理类LogProxy 实现日志的输出。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
import com.gc.impl.TimeBookInterface;
import com.gc.action.LogProxy;
public class TestHelloWorld {
         public static void main(String[ ] args) {
           //实现了对日志类的重用
           LogProxy logProxy  = new LogProxy();
TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy.bind(new TimeBook());
timeBookProxy.doAuditing("张三");
    }
}
(5)运行测试程序,可以得到通过LogProxy类输出日志信息,如图5.3所示。
图5.3  通过LogProxy类输出日志信息
这种方式,对于其他的类也同样适用,这样就真正地实现了业务逻辑和输出日志信息代码的分离。
  对这3种实现方式进行总结
第一种方式,需要在每个类里都增加对输出日志信息的代码;第二种方式,虽然实现了业务逻辑与输出日志信息代码的分离,但还是必须依赖于固定的接口;第三种方式,真正实现了对输出日志信息代码的重用,并且不依赖于固定的接口实现。
从第三种方式中,也可以看出Java动态代理机制的强大,而Spring的AOP正是建立在Java动态代理的基础上的,当读者通过上面的示例一步一步地对Java的动态代理机制有了一定的了解后,接下来就可以逐渐地进入AOP了。

Java之动态代理类实现日志简单实例

开心一笑上课呢,同桌撕了一片纸放嘴里了咬了咬,又吐回了手里。 揉了揉,揉成个球状,然后又把这东西给放嘴里,咽下去了。 我问:你干嘛呢? 这二货幽幽地说:这两天有点感冒,捏个药丸吃。提出问题Jav...
  • huangwenyi1010
  • huangwenyi1010
  • 2016年07月01日 07:17
  • 1254

动态代理实现日志的写入

之前在学习设计模式的时候就学习过代理模式,在DRP的学习过程中,又一次遇到了代理模式,但是这次接触到的是动态代理。做项目的时候也听同学们提到过AOP,那么动态代理和AOP是一种什么样的关系呢?    ...
  • zjx86320
  • zjx86320
  • 2015年03月31日 16:39
  • 2224

java代理机制

关于java代理主要涉及到静态代理、动态代理,其中动态代理又有JDK动态代理及CGLIB代理。 代理实现 静态代理       代理类StaticProxy与被代理类TestImpl实现相同的接口,在...
  • Architect0719
  • Architect0719
  • 2016年04月24日 17:36
  • 589

Spark日志分析案例

SparkCore日志分析主程序 package com.ibeifeng.bigdata.spark.app.core import org.apache.spark.{SparkContext,...
  • Gerry199102
  • Gerry199102
  • 2016年07月18日 08:46
  • 4170

JAVA反射机制与动态代理

在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的...
  • liuganggao
  • liuganggao
  • 2015年03月09日 16:54
  • 2655

Java代理模式详解及案例分析:静态代理/动态代理

标题:Java代理模式详解及案例分析:静态代理/动态代理 我们以几个问题,来开始我们今天的学习,如果下面几个问题,你都能说出个一二,那么恭喜你,你已经掌握了这方面的知识。 1,什么是代理模式? 2,...
  • reggergdsg
  • reggergdsg
  • 2016年11月03日 19:56
  • 1392

java 动态代理机制的理解和分析

引言 Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执...
  • Leonardo9029
  • Leonardo9029
  • 2016年03月28日 10:22
  • 3380

java高级---->Java动态代理的原理

Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程...
  • GarfieldEr007
  • GarfieldEr007
  • 2016年12月18日 11:06
  • 317

java动态代理详解,并用动态代理和注解实现日志记录功能

动态代理的概念       动态代理是程序在运行过程中自动创建一个代理对象来代替被代理的对象去执行相应的操作,例如, 我们有一个已经投入运行的项目中有一个用户DAO类UserDao用来对User对象进...
  • han_han_1
  • han_han_1
  • 2015年07月04日 11:39
  • 2605

nginx日志分析利器GoAccess

转自:http://www.cnblogs.com/yjf512/p/3640346.htm 面试的时候一定会被面到的问题是:给出web服务器的访问日志,请写一个脚本来统计访问前10的IP有哪...
  • lgq421033770
  • lgq421033770
  • 2016年05月27日 10:06
  • 2012
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:从一个输出日志的实例分析Java的代理机制
举报原因:
原因补充:

(最多只允许输入30个字)