Spring中使用动态代理实现环绕通知


引言:

因为环绕通知类似于动态代理的全过程,所以可以使用动态代理技术实现类似的环绕通知

  • ArithmeticCalculator.java
  • ArithmeticCalculatorImpl.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;
    }
}

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;

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 = null;
                try {
                    //前置通知,类似于@Before注解
                    result = method.invoke(target, args);
                    //返回通知,可以访问到方法的返回值,类似于@AfterReturning注解
                } catch (Exception e) {
                    e.printStackTrace();
                    //异常通知,可以访问到方法出现的异常,类似于@AfterThrowing注解
                }
                //后置通知,因为方法可能会出异常,所以访问不到方法的返回值,类似于@After注解

                //日志
                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) {
        //通过使用动态代理的方式实现环绕通知
        ArithmeticCalculator target = new ArithmeticCalculatorImpl();
        ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();
        int result = proxy.add(1, 2);
        System.out.println("-->" + result);
        result = proxy.div(4, 2);
        System.out.println("-->" + result);

    }
}

文章作者: YangChongZhi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 YangChongZhi !
评论
 上一篇
收集常用的网站(持续更新...) 收集常用的网站(持续更新...)
引言: 对一些常用网站的收集(主要是为了方便自己换电脑时懒得去导出浏览器收藏夹),会持续更新… 常用网站 软件安装管家(能找到满足日常办公的很多软件) chm格式的java API制作工具 浏览器主页“简法主页” 浏览器主页插件 itab
2020-03-31
下一篇 
Spring AOP的环绕通知@Around Spring AOP的环绕通知@Around
引言: Spring AOP可以使用@Around注解来实现环绕通知,环绕通知需要携带ProceedingJoinPoint类型的参数,环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法
2020-03-11
  目录