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. Java中单列集合List排序的真实应用场景

    一.需求描述 最近产品应客户要求提出了一个新的需求,有一个列表查询需要按照其中的多列进行排序. 二.需求分析 由于数据总量不多,可以全部查询出来,因此我就考虑使用集合工具类Collections.so ...

  2. Ansible学习分享(基本)

    背景:Teamleader提到一款好用的自动化配置管理工具,于是前去学习实践,有了下面分享. 纲要 一.Ansible简介 二.Ansible准备 2.1 Ansible安装 2.2 设置SSH公钥验 ...

  3. Java,用户刷屏检测\相似字符串检测

    背景 近期有几个业务方提出一需求,期望判断一个用户在短期内是否存在刷屏现象,出现后能对其做出限制,并上报. 刷屏定义:取出用户近期20条评论,如果有50%的评论是"相似"的,则认为 ...

  4. openresty 学习笔记六:使用session库

    openresty 学习笔记六:使用session库 lua-resty-session 是一个面向 OpenResty 的安全和灵活的 session 库,它实现了 Secure Cookie Pr ...

  5. 八、Pandas 表格处理

    pandas有两个数据结构,一个是series 另一个是DataFrame from matplotlib import pyplot as plt import numpy as np import ...

  6. SQL Server 将两行或者多行拼接成一行数据

    一个朋友,碰到一个问题. 就是查询出来的结果集,需要每隔三行.就将这三行数据以此拼接为一行显示.起初我想着用ROW_NUMBER加CASE WHEN去做,发现结果并非我预期那样. 结果如下: 由于别人 ...

  7. The Superego 实验四 团队作业1:软件研发团队组建

    项目 内容 课程班级博客链接 班级博客链接 这个作业要求链接 作业要求链接 团队名称 The Superego 团队的课程学习目标 (1)组建团队,建设团队文化,申请开通团队博客 (2)团队之间相互协 ...

  8. CUDA运行时 Runtime(一)

    CUDA运行时 Runtime(一)             一. 概述 运行时在cudart库中实现,该库通过静态方式链接到应用程序库cudart.lib和libcudart.a,或动态通过cuda ...

  9. 编译原理-非确定有穷自动机(nondeterministic finite automata,NFA)

    是一个五元组,M=(S,∑,f,S0,F) S:有穷状态集 ∑:输入字母表(有穷) f:f(S,α)=S' 表示从一个状态S出发,识别了一个字α后,可以到达S'这个状态集合之间的某一个状态(可能的后继 ...

  10. v-for和v-if不能同时使用

    如果使用v-for遍历数据时,想筛选出URL不为空的项并进行渲染 <ul> <li v-for="(item,index) in list" v-if=" ...