Spring笔记本(3)

本文详细介绍了Spring的AOP编程,包括AOP的专业术语如通知、切面、连接点等,并展示了如何使用代理实现日记功能,以及如何获取拦截方法的返回值和异常信息。此外,还探讨了Spring的环绕通知及其注意事项。
摘要由CSDN通过智能技术生成
AOP切面编程

AOP是面向切面编程。全称:AspectOriented Programming

面向切面编程指的是:程序是运行期间,动态地将某段代码插入到原来方法代码的某些位置中。这就叫面向切面编程。

一个简单计算数功能加日记

准备计算器相关类

计算接口

publicinterface Calculate {

   publicint add(int num1, int num2);

 

   publicint mul(int num1, int num2);

 

   publicint div(int num1, int num2);

 

   publicint sub(int num1, int num2);

}

 

计算机类

publicclass Calculator implements Calculate {

   publicint add(int num1, int num2) {

      System.out.println("日记 :【add】方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2);

      return num1 + num2;

   }

 

   publicint mul(int num1, int num2) {

      System.out.println("日记 :【mul】方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2);

      return num1 * num2;

   }

 

   publicint div(int num1, int num2) {

      System.out.println("日记 :【div】方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2);

      return num1 / num2;

   }

 

   publicint sub(int num1, int num2) {

      System.out.println("日记 :【sub】方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2);

      return num1 - num2;

   }

}

 

测试的代码

publicclass CalculatorTest {

   publicstaticvoid main(String[] args) {

      Calculate calculate = new Calculator();

      int result =calculate.add(12, 12);

      System.out.println("相加的结果:" + result);

     

      result = calculate.mul(12, 12);

      System.out.println("相乘的结果:" + result);

   }

}

 

上面这种方法加日记处理操作。日记的代码就会耦合到业务代码中。而且后期如果需要修改日记就需要去指的修改所有方法中的日记操作。这个维护操作非常不方便。

可以说是一个很失败的例子。

原始方法统一日记处理。

把日记的内容封装到一个类去中集中处理。

 

编写一个日记处理工具类

publicclass LogUtil {

   publicstaticvoid log(String method, int num1, int num2) {

      System.out.println("日记 :【" + method + "】 方法调用前 。参数1是:" + num1 + " , 参数2是:" + num2);

   }

}

 

修改原来Calculator中的日记代码

   @Override

   publicint add(int num1, int num2) {

      LogUtil.log("add", num1, num2);

      return num1 + num2;

   }

 

   @Override

   publicint mul(int num1, int num2) {

      LogUtil.log("mul", num1, num2);

      return num1 * num2;

   }

 

但是这种方式的不足之处是,每有一个需要加日记的类,都需要到类的代码中去添加日记功能代码。

无法做到所有对象都统一处理。

使用代理实现日记

使用jdk动态代理统一日记

创建一个计算器代理工具类

publicclass CalculateProxyFactory {

 

   publicstatic CalculategetProxy(Calculate target) {

      // 定义一个计算器拦截处理类

      classCalculateInvocationHandler implements InvocationHandler{

         Calculate target;

 

         publicCalculateInvocationHandler(Calculate calculate) {

            this.target = calculate;

         }

 

         /**

          * proxy 代理对象

          * method 调用的方法

          * args     方法的参数

          */

         @Override

         public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {

            if(method.getDeclaringClass().equals(Object.class)) {

               return method.invoke(target, args);

            }

            LogUtil.log(method.getName(),(int) args[0], (int) args[1]);

            Object result = null;

            try {

               result = method.invoke(target, args);

               System.out.println("后置日记");

            } catch (Exception e) {

               System.out.println("异常日记");

            } finally {

               System.out.println("finally日记");

            }

            return result;

         }

      }

 

      return (Calculate) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass()

            .getInterfaces(), newCalculateInvocationHandler(target));

   }

 

}

 

修改原来计算器中的日记代码

publicclass Calculator implements Calculate {

   @Override

   publicint add(int num1, int num2) {

      return num1 + num2;

   }

 

   @Override

   publicint mul(int num1, int num2) {

      return num1 * num2;

   }

 

   @Override

   publicint div(int num1, int num2) {

      return num1 / num2;

   }

 

   @Override

   publicint sub(int num1, int num2) {

      return num1 - num2;

   }

}

 

测试代码调整

   publicstaticvoid main(String[] args) {

      Calculatecalculate = CalculateProxyFactory.getProxy(new Calculator() );

      int result = calculate.add(12,12);

      System.out.println("相加的结果:" + result);

     

      result= calculate.mul(12, 12);

      System.out.println("相乘的结果:" + result);

   }

 

优点:这种方式已经解决我们前面所有日记需要的问题。非常的灵活。而且可以方便的在后期进行维护和升级。

缺点:当然使用jdk动态代理,需要有接口。如果没有接口。就无法使用jdk动态代理。

使用cglib代理

 

publicclass CGLibProxyFactory implements MethodInterceptor {

 

   publicstatic ObjectgetCGLibProxy(Object target, Callback callback) {

      // 创建一个CGLig生成器

      Enhancerenhancer = new Enhancer();

      // 设置父类。因为cglib是通过类,进行代码,不是通过接口

      enhancer.setSuperclass(target.getClass());

      // 设置拦截的代理方法

      enhancer.setCallback(callback);

      // create 方法创建一个代理对象并返回

      return enhancer.create();

   }

 

   @Override

   public Objectintercept(Object proxy, Method method, Object[] params, MethodProxymethodProxy)

         throws Throwable {

      LogUtil.log(method.getName(), (int) params[0], (int) params[1]);

      // 调用实际的对象的方法

      // 一定要使用methodProxy对象

      // 第一个参数是proxy代码对象的父类方法

      Objectresult = methodProxy.invokeSuper(proxy, params);

      System.out.println("这是后置代码");

 

      return result;

   }

 

   publicstaticvoid main(String[] args) {

      Calculatorcalculator = (Calculator) CGLibProxyFactory.getCGLibProxy(new Calculator(),

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值