• 学习AOP之JAVA的代理机制


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

    一、通用的日志输出方法  :需要在每个类里都增加对输出日志信息的代码

    二、通过面向接口编程实现日志的输出(JAVA的静态代理):虽然实现了业务逻辑与输出日志信息的分离,但必须依赖固定的接口

    三、使用JAVA的代理机制进行日志输出(JAVA的动态代理):真正实现了对输入日志信息代码的重用,并且不依赖于固定的接口实现

    通用的日志输出方法:

    在每一个业务逻辑方法里编写记录日志的代码

     1 //*****TimeBook.java*******
     2 import org.apache.log4j.Level;
     3 import org.apache.log4j.Logger;
     4 public class TimeBook{
     5       private Logger logger = Logger.getLogger(this.getClass().getName());
     6       //审核数据的相关程序
     7       public void doAuditing(String name){
     8           logger.log(Level.INFO,name+" 开始审核数据...");
     9           //审核数据的相关程序
    10           ...
    11          logger.log(Level.INFO,name+" 审核数据结束...");  
    12   
    13 }         
    14 }           

    如上示例代码,日志信息添加到具体的业务逻辑中,如果程序中其他代码需要日志输出的功能,那么每个程序都要添加和上面类似的代码。

    这样在程序中,就会存在很多类似的日志输出代码,造成很大的耦合。我们通过面向接口编程改进这个问题。

    通过面向接口编程实现日志的输出:

    1.首先把doAuditing()方法提取出来成为接口,然后通过一个实体类实现这个方法,在这个方法里编写具体的业务逻辑代码

    接口和实现接口类

    2.通过一个代理类来进行日志输出

     1 //******TimeBookProxy.java*****
     2 package com.gc.action;
     3 import org.apache.log4j.Level;
     4 import org.apache.log4j.Logger;
     5 
     6 import com.gc.impl.TimeBookInterface;
     7 
     8 public class TimeBookProxy{
     9       private Logger logger = Logger.getLogger(this.getClass().getName);
    10       private TimeBookInterface timeBookInterface;
    11      //在该类中针对前面的接口编程,而不针对具体的类
    12       public TimeBookProxy(TimeBookInterface timeBookInterface)
    13      {
    14             this.timeBookInterface = timeBookInterface;
    15      }
    16      //实际业务处理
    17     public void doAuditing(String name){
    18             logger.log(Level.INFO,name+" 开始审核数据...");
    19             timeBookInterface.doAuditing(name);
    20             logger.log(Level.INFO,name+" 审核数据结束...");
    21     }
    22 }

    3.编写测试程序

     1 //****TestHelloWorld.java******
     2 package com.gc.test;
     3 import com.gc.action.TimeBook;
     4 import com.gc.action.TimeBookProxy;
     5 public class TestHelloWorld{
     6       public static void main(String[] args){
     7             TimeBookProxy timeBookProxy = new TimeBookProxy(new TimeBook());
     8             timeBookProxy.doAuditing("victory");   
     9       }
    10 }

     和前面一个日志做对比,可以看到在这个示例中,具体的业务逻辑代码和日志信息代码分离开了,只要实现了接口TimeBookInterface的类,都可以通过

    代理类TimeBookProxy实现日志信息的输出,而不用再每个类里面都写日志信息输出的代码,从而实现了日志信息的代码重用。

    使用JAVA的代理机制进行日志输出:

    上面代码仍然有一些局限性,因为要使用代理类,就必须要实现固定的接口,有没有一种通用的机制,不管是不是实现这个接口,都可以实现日志信息的输出?

    JAVA提供的InvocationHandler接口可以实现这种功能

    1.编写一个日志信息的代理类,这个代理类实现接口InvocationHandler

     1 //****LogProxy.java****
     2 package com.gc.action;
     3 
     4 import java.lang.reflect.InovationHandler;
     5 import java.lang.reflect.Method;
     6 import java.lang.reflect.Proxy;
     7 
     8 import org.apache.log4j.Level;
     9 import org.apache.log4j.Logger;
    10 //代理类实现了接口InvocationHandler
    11 public class LogProxy implement InvocationHandler{
    12         private Logger logger = Logger.getLogger(this.getClass().getName());
    13         private Object obj;
    14         //绑定代理对象
    15         public Object bind(Object obj){
    16               this.obj = obj;
    17               return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInstances(),this);
    18         }
    19        //针对接口编程
    20       public Object invoke(Object proxy,Method method,Object[] args) throw Throwable{
    21            Object result = null;
    22            try{
    23                 //在方法调用前后进行日志输出
    24                logger.log(Level.INFO,args[0]+"开始审核数据...");
    25                result = method.invoke(obj,args);
    26                logger.log(Level.INFO,args[0]+"审核数据结束...");
    27 
    28            }
    29           catch(Exception e){
    30                logger.log(Level.INFO,e,toString());
    31           }
    32           return result;
    33       }
    34 }    

    2.编写一个接口,并实现这个接口,在实现类中编写具体的考勤审核代码

    参看以上代码  接口和实现接口类

    3.编写测试类,查看测试结果

     1 //*******TestHelloWorld.java*****
     2  
     3 package com.gc.test;
     4 import com.gc.action.TimeBook;
     5 import com.gc.action.TimeBookProxy;
     6 import com.gc.impl.TimeBookInterface;
     7 import com.gc.action.LogProxy;
     8 public class TestHelloWorld{
     9      public static void mian(String[] args)
    10      {
    11          //实现了对日志类的重用
    12          LogProxy logProxy = new LogProxy();
    13          TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy.bind(new TimeBook());
    14         timeBookProxy.doAuditing("victory");
    15     }
    16 }
  • 相关阅读:
    某图片网站整合yolo图片特征相似图片获取
    MySQL导入数据报错 ERROR 1794 (HY000) at line 22 -- 解决
    apache-commons-lang3之StringUtils使用集锦
    swf格式的flash文件变更md5
    Linux常见场景的shell使用
    tp5在apache下能访问,但放到nginx下报404
    template-web.js 使用二
    jquery实现动态添加html代码
    JQuery的父、子、兄弟节点
    this
  • 原文地址:https://www.cnblogs.com/victoria-c/p/5655359.html
Copyright © 2020-2023  润新知