AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

  AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理(编译时增强)和动态代理(运行时增强),静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。

(1)使用AspectJ的编译时增强实现AOP

  所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。

  举个实例的例子来说。首先我们有一个普通的Hello类
  public class Hello {
    public void sayHello() {
      System.out.println("hello");
    }
    public static void main(String[] args) {
      Hello h = new Hello();
      h.sayHello();
    }
  }

  使用AspectJ编写一个Aspect
    public aspect TxAspect {
      void around():call(void Hello.sayHello()){
        System.out.println("开始事务 ...");
        proceed();
        System.out.println("事务结束 ...");
      }
     }

  编译完成之后再运行这个Hello类,可以看到以下输出
    开始事务 ...
    hello
    事务结束 ...

  很显然,AOP已经生效了,那么究竟AspectJ是如何在没有修改Hello类的情况下实现代码增强的?
  查看一下编译后的Hello.class
    public class Hello {
      public Hello() {
      }
      public void sayHello() {
        System.out.println("hello");
      }
      public static void main(String[] args) {
        Hello h = new Hello();
          sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null);
      }
    }

  如此,proceed()方法就是回调执行被代理类中的方法。

(2)使用Spring AOP

  Spring AOP使用的动态代理,动态代理就是说AOP不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。需导入两个jar包:cglib.jar、asm.jar。

  Spring AOP中的动态代理主要有两种方式:jdk动态代理 、cglib动态代理。jdk动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。jdk动态代理的核心是InvocationHandler接口 、Proxy类。

  当目标类没有实现接口,那么Spring AOP会选择使用cglib来动态代理目标类。cglib(Code Generation Library)是一个代码生成的类库,可以在运行时动态的生成某个类的子类,cglib是通过继承的方式做的动态代理,所以若某个类被标记为final,那么它就无法使用cglib做动态代理的。

  定义一个接口
  public interface Person {
    String sayHello(String name);
  }

  实现类
  @Component
  public class Chinese implements Person {
    @Override
    public String sayHello(String name) {
      System.out.println("-- sayHello() --");
      return name + " hello, AOP";
    }
  }

  

  实现类

  public class MyInvocationHandler implements InvocationHandler {
     private Object target;
     MyInvocationHandler() {
      super();
    }
    MyInvocationHandler(Object target) {
      super();
      this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      // 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
      System.out.println("before-----------------------------");
      // 程序执行
      Object result = method.invoke(target, args);
      // 程序执行后加入逻辑,MethodAfterAdviceInterceptor
      System.out.println("after------------------------------");
      return result;
    }
  }

  测试类 

  public class Test {
  /**
  * JDK动态代理测试类
  */
  public static void main(String[] args) {
    Chinese chinese= new Chinese();
    MyInvocationHandler mih = new MyInvocationHandler(chinese);
    Class<?> cls = chinese.getClass();
    /**
    * loader 类加载器
    * interfaces 实现接口
    * h InvocationHandler
    */
    Person p = (Person)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
    System.out.println(p.sayHello("张三"));
    }
  }

  输出

  before-----------------------------

  张三 hello, AOP

  after------------------------------

  

  我们再来看看不是用接口的情况,修改Chinese类

  实现类
  @Component
  public class Chinese {
    public String sayHello(String name) {
      System.out.println("-- sayHello() --");
      return name + " hello, AOP";
    }
  }

  

  实现类 

  public class CglibProxy implements MethodInterceptor {
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      System.out.println("before-------------");
      // 执行目标类add方法
      proxy.invokeSuper(object, args);
      System.out.println("after--------------");
      return null;
    }
  }

  目标类的工厂Factory类

  public class Factory {
    //获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
    public static Base getInstance(CglibProxy proxy) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(Chinese.class);
      //回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
      enhancer.setCallback(proxy);
      // 此刻,base不是单纯的目标类,而是增强过的目标类
      Chinese chinese = (Chinese) enhancer.create();
      return chinese;
    }
  }

  测试类  

  public class Test {
    public static void main(String[] args) {
      CglibProxy proxy = new CglibProxy();
      // base为生成的增强过的目标类
      Chinese chinese = Factory.getInstance(proxy);
      System.out.println(chinese.sayHello("张三"));
    }
  }

  输出

  before-----------------------------

  张三 hello, AOP

  after------------------------------

AOP面向切面的实现的更多相关文章

  1. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  2. AOP面向切面编程的四种实现

     一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...

  3. Javascript aop(面向切面编程)之around(环绕)

    Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被 ...

  4. Method Swizzling和AOP(面向切面编程)实践

    Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...

  5. [转] AOP面向切面编程

    AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...

  6. C# AOP 面向切面编程之 调用拦截

    有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...

  7. 【原创】Android AOP面向切面编程AspectJ

    一.背景: 在项目开发中,对 App 客户端重构后,发现用于统计用户行为的友盟统计代码和用户行为日志记录代码分散在各业务模块中,比如在视频模块,要想实现对用户对监控点的实时预览和远程回放行为进行统计, ...

  8. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...

  9. 论AOP面向切面编程思想

    原创: eleven 原文:https://mp.weixin.qq.com/s/8klfhCkagOxlF1R0qfZsgg [前言] AOP(Aspect-Oriented Programming ...

  10. 学习笔记: AOP面向切面编程和C#多种实现

    AOP:面向切面编程   编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统      类--砖头     系统--房子      类--细胞     系统--人    ...

随机推荐

  1. KEIL中查看程序存储空间的大小

    Program Size: Code=86496 RO-data=9064 RW-data=1452 ZI-data=16116 Code是代码占用的空间,RO-data是 Read Only 只读常 ...

  2. 3.20 tr:替换或删除字符

    tr命令 从标准输入中替换.缩减或删除字符,并将结果写到标准输出. tr [option] [SET1]  [SET2] tr [选项]   [字符1]  [字符2]   -d    删除字符 -s  ...

  3. Java 的序列化 (Serializable)(Day_09)

    我们的火,要把世界都点燃 运行环境 JDK8 + IntelliJ IDEA 2018.3 什么是序列化,反序列化 序列化是将对象状态转换为可保持或传输的格式的过程. 与序列化相对的是反序列化,它将流 ...

  4. 使用python实现钉钉告警通知功能

    前言:日常工作中告警通知是必不可少的,一般会使用邮件.钉钉.企业微信等,今天分享一下使用python实现钉钉告警 一. 钉钉机器人创建 登录钉钉客户端,创建一个群,把需要收到报警信息的人员都拉到这个群 ...

  5. String 是一个奇怪的引用类型

    开局两张图,内容全靠刷! 马甲哥看到这样的现象,一开始还是有点懵逼. 这个例子,string是纯粹的引用类型,但是在函数传值时类似于值传递: 我之前给前后示例的内存变化图吧: 根因就是大多数高级语言都 ...

  6. 我眼中的WebViewJavascriptBridge(图解)

    工作中涉及到一段时间iOS开发,在开发中有个小小的框架让我非常深刻,就是WebViewJavascriptBridge,用于原生控件与前端交互通信.我觉得WebViewJavascriptBridge ...

  7. Lidar激光雷达市场

    Lidar激光雷达市场 近年来,激光雷达技术在飞速发展,从一开始的激光测距技术,逐步发展了激光测速.激光扫描成像.激光多普勒成像等技术,如今在无人驾驶.AGV.机器人等领域已相继出现激光雷达的身影. ...

  8. 字符识别OCR原理及应用实现

    字符识别OCR原理及应用实现 文本是人类最重要的信息来源之一,自然场景中充满了形形色色的文字符号.光学字符识别(OCR)相信大家都不陌生,就是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过 ...

  9. 自定义 DataLoader

    自定义 DataLoader 如 数据输入 一文所介绍,OneFlow 支持两种数据加载方式:直接使用 NumPy 数据或者使用 DataLoader 及其相关算子. 在大型工业场景下,数据加载容易成 ...

  10. 基于C语言文件操作的学生成绩管理系统

    原理 在一个班级学生成绩管理系统中,希望处理每个学生的学习情况信息,其中包括学生的学号.姓名.各科名称和成绩等并能使管理人员通过界面完成对学生信息的录入及对学生信息的录入及对数据的查找.浏览.插入.排 ...