使用动态代理解决方法调用前后添加日志信息

Posted chenwh_123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用动态代理解决方法调用前后添加日志信息相关的知识,希望对你有一定的参考价值。

  一般情况,在每个调用的方法中直接添加日志信息,存在如下问题:

1.代码混乱:越来越多的非业务需求加入(如日志和验证等)后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点;

2.代码分散:以日志需求为例,只是为了满足这个单一的需求,就不得不在多个模块里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有的模块。

针对以上问题,使用动态代理带解决。

代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象。任何原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

1.先定义一个接口

public interface Calc {
    int add(int i,int j);
    int sub(int i,int j);
    int multi(int i,int j);
    int div(int i,int j);

}

2.定义一个接口的实现类,如

public class CalcImpl implements Calc{

    public int add(int i, int j) {
        int result =i+j;
        return result;
    }

    public int sub(int i, int j) {
        int result =i-j;
        return result;
    }

    public int multi(int i, int j) {
        int result =i*j;
        return result;
    }

    public int div(int i, int j) {
        int result =i/j;
        return result;
    }

}

3.定义代理类

public class CalcLoggingProxy {
 //要代理的对象
  private Calc target;
  public CalcLoggingProxy(Calc target) {
    this.target=target;
    }
  public Calc getLoggingProxy(){
      Calc proxy=null;
      //代理对象由哪一个类加载器加载
      ClassLoader loader=target.getClass().getClassLoader();
      //代理对象的类型,即其中有哪些方法
      Class[] interfaces = new Class[]{Calc.class};
     //当调用代理对象其中的方法试,就执行该方法
    InvocationHandler h=new InvocationHandler() {
        /**
         * proxy:正在返回的代理对象,一般情况下很少使用
         * method:正在调用的方法
         * args:调用方法时,传入的参数
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            System.out.println("the method "+method.getName() +" begin with"+ Arrays.asList(args));
            //执行target的方法,即执行代理对象的方法
            Object result=method.invoke(target, args);
            System.out.println("the method "+method.getName() +" end with "+result);
            return result;
        }
    };
        proxy=(Calc) Proxy.newProxyInstance(loader, interfaces, h);
        return proxy;
  }
}

4.写个main方法测试效果

    public static void main(String[] args) {
        Calc target =new CalcImpl();
        Calc proxy =new CalcLoggingProxy(target).getLoggingProxy();
        int result=proxy.add(1, 2);
        System.out.println("--->"+result);
    }

结果如下:

the method add begin with[1, 2]
the method add end with 3
--->3

用动态代理可以解决问题,但是用过spring的同学,肯定非常清楚spring中的AOP能轻松的解决此问题。

以上是关于使用动态代理解决方法调用前后添加日志信息的主要内容,如果未能解决你的问题,请参考以下文章

3-java安全基础——jdk动态代理

java 动态代理

java动态代理技术

java动态代理技术

深入理解代理模式原理与技术

MybtaisMybatis 插件 Plugin开发动态代理步步解析