Spring中使用动态代理解决日志需求


引言:

使用动态代理技术实现在类的方法中加入日志信息。通过动态代理的方式写入日志信息不会给原来的类带来代码混乱和分散的问题,便于维护

  • ArithmeticCalculator.java
  • ArithmeticCalculatorImpl.java
  • ArithmeticCalculatorLoggingImpl.java
  • ArithmeticCalculatorLoggingProxy.java
  • Main.java

ArithmeticCalculator.java

package com.yczlab.spring.aop.helloworld;

public interface ArithmeticCalculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

ArithmeticCalculatorImpl.java

package com.yczlab.spring.aop.helloworld;

//该实现类的方法中不带日志信息,而通过动态代理的方式写入日志信息,便于维护
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

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

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

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

ArithmeticCalculatorLoggingImpl.java

package com.yczlab.spring.aop.helloworld;

//直接在该实现类的方法中写入日志信息
public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        System.out.println("The method add() begins with[" + i + "," + j + "]");
        int result = i + j;
        System.out.println("The method add() ends with " + result);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("The method sub() begins with[" + i + "," + j + "]");
        int result = i - j;
        System.out.println("The method sub() ends with " + result);
        return result;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("The method mul() begins with[" + i + "," + j + "]");
        int result = i * j;
        System.out.println("The method mul() ends with " + result);
        return result;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("The method div() begins with[" + i + "," + j + "]");
        int result = i / j;
        System.out.println("The method div() ends with " + result);
        return result;
    }
}

ArithmeticCalculatorLoggingProxy.java

package com.yczlab.spring.aop.helloworld;

import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;

import java.lang.reflect.Method;
import java.util.Arrays;

//使用该动态代理类,解决ArithmeticCalculatorImpl类方法中的日志问题
public class ArithmeticCalculatorLoggingProxy {

    //要代理的对象
    private ArithmeticCalculator target;

    public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
        this.target = target;
    }

    public ArithmeticCalculator getLoggingProxy() {
        ArithmeticCalculator proxy = null;

        //代理对象有哪一个类加载器负责加载
        ClassLoader loader = target.getClass().getClassLoader();
        //代理对象的类型,即其中有哪些方法。可以通过ArithmeticCalculator.class.getMethods()返回一个方法数组Method[]
        Class[] interfaces = new Class[]{ArithmeticCalculator.class};
        //当调用代理对象其中的方法时,该执行的代码
        InvocationHandler h=new InvocationHandler() {
            /*
            * proxy:正在返回的那个代理对象,一般情况下,invoke方法中都不使用该对象。
            * method:正在被调用的方法
            * args:调用方法时,传入的参数
            * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //在这里使用proxy时会出现死循环,StackOverflowError。因为一旦使用,又会被动态代理转移到这儿调用invoke,出现死循环
                //System.out.println(proxy.toString());

                String methodName = method.getName();//获取方法名
                //日志
                System.out.println("<-yczlab-> The method " + methodName + " begins with " + Arrays.asList(args));
                //执行方法
                Object result = method.invoke(target, args);
                //日志
                System.out.println("<-yczlab-> The method " + methodName + "ends with " + result);
                return result;
            }
        };
        proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);

        return proxy;
    }

}

Main.java

package com.yczlab.spring.aop.helloworld;

public class Main {
    public static void main(String[] args) {
        //直接在实现类ArithmeticCalculatorLoggingImpl的方法中写日志信息
        ArithmeticCalculator arithmeticCalculatorLogging;
        arithmeticCalculatorLogging = new ArithmeticCalculatorLoggingImpl();
        int result = arithmeticCalculatorLogging.add(1, 2);
        System.out.println("-->" + result);
        result = arithmeticCalculatorLogging.div(4, 2);
        System.out.println("-->" + result);

        System.out.println("***********************************");
        //通过使用动态代理的方式写入日志信息
        ArithmeticCalculator target = new ArithmeticCalculatorImpl();
        ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();
        result = proxy.add(1, 2);
        System.out.println("-->" + result);
        result = proxy.div(4, 2);
        System.out.println("-->" + result);

    }
}

文章作者: YangChongZhi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 YangChongZhi !
评论
 上一篇
Spring AOP的相关基础介绍 Spring AOP的相关基础介绍
引言: Aop(Aspect-Oriented Programming,面向切面编程)是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充 AOP简介 AOP主要编程对象是切面(a
2020-03-09
下一篇 
Spring中的泛型依赖注入 Spring中的泛型依赖注入
引言: Spring可以为子类注入子类对应的泛型类型的成员变量的引用 User.java BaseService.java UserService.java BaseRepository.java UserRepository.java
2020-03-08
  目录