Spring 的 AOP 概述和底层实现

1. 什么是 AOP

  • AOP (Aspect Oriented Programing),即面向切面编程
  • AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
  • Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

简单的来说就是:

生成和目标类一样的类或者继承目标类,生成子类,我们都把该类叫做代理类,然后通过代理方式在代理类中添加方法,以达到对目标类中的方法进行增强的目的。


2. AOP 相关术语

Joinpoint(连接点):

所谓连接点是指那些可以被拦截的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。

比如增删改查这些方法都可以增强,这些方法称为是连接点。

Pointcut(切入点):

指的是真正被拦截的点。

比如我们只想对类中的 save() 方法进行增强(做权限校验),save 方法称为是切入点。

Advice(通知/增强):

指拦截到 Joinpoint 之后所要做的事。

通知分为前置通知(方法执行之前)、后置通知(方法执行之后)、异常通知、最终通知、环绕通知(切面要完成的功能)

比如对 save 方法要进行权限校验,权限校验的方法称为是通知。

Introduction(引介):

引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。

Target(目标对象):

代理(被增强)的目标对象。

Weaving(织入):

是指把增强(Advice)应用到目标对象(Target)来创建新的代理对象的过程。

比如将权限校验应用到 UserDaoImplsave 方法的这个过程。

Proxy(代理):

一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect(切面):

是切入点和通知(引介)的结合。


3. Spring 的底层实现原理

两种实现:
  • JDK 动态代理
  • CGLIB生成代理
JDK 动态代理:
public class MyJdkProxy implements InvocationHandler{

    private UserDao userDao;

    public MyJdkProxy(UserDao userDao) {
this.userDao = userDao;
} public Object createProxy() {
// 获得目标类
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
return proxy;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 对 save 进行增强
if ("save".equals(method.getName())) {
System.out.println("权限校验...");
// args 参数化,UserDao中方法列表
return method.invoke(userDao, args);
} // invoke 调用 UserDao 中的方法
return method.invoke(userDao, args);
}
}

其中:

Proxy.newProxyInstance(); 方法需要传入三个参数:类的加载器,类实现的接口,InvocationHandler 的接口。三个参数:

  • userDao.getClass().getClassLoader()
  • userDao.getClass().getInterfaces()
  • 通过匿名内部类或使用 implements InvocationHandler 接口,再通过 this 实例化

然后在测试类中 new 代理类,这样我们在测试类中调用实现类中的方法就相当于变成了调用动态代理类中的 invoke 方法。

注意:

JDK 动态代理是对实现接口类实行代理,建立一个实现目标类中方法的代理类。(面向接口)

具体代码:MyJdkProxy.java

CGLIB生成代理:
public class MyCglibProxy implements MethodInterceptor{

    private ProductDao productDao;

    public MyCglibProxy(ProductDao productDao) {
this.productDao = productDao;
} public Object createProxy() {
//1. 创建核心类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(productDao.getClass());
//3. 设置回调
enhancer.setCallback(this);
//4. 生成代理(子类)
Object proxy = enhancer.create();
return proxy;
}
//回调函数中实例化 MethodInterceptor 接口方法(intercept, 类似于 invoke 方法),通过 this
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("权限校验=========");
}
// invokeSuper 调用父类 ProductDao 方法
return methodProxy.invokeSuper(proxy, args);
}
}
  • 对于不使用接口的业务类,无法使用 JDK 动态代理
  • CGLIB 采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题

注意:

CGLIB 实现和 JDK 动态代理不同,是生成一个类来继承目标类。


4. 代理知识总结

  • 程序中应优先对接口创建代理,便于程序解耦维护
  • 标记为 final 的方法,不能被代理,因为无法进行覆盖
    • JDK 动态代理,是针对接口生成子类,接口中方法不能使用 final 修饰
    • CGLIB 是针对目标类生成子类,因此类或方法不能使用 final
  • Spring 只支持方法连接点,不提供属性连接

具体代码:MyCglibProxy.java


附:

spring 核心包有四个:

  • spring-context
  • spring-beans
  • spring-expression
  • spring-core

Spring 的 AOP 概述和底层实现的更多相关文章

  1. spring(二) AOP之AspectJ框架的使用

    前面讲解了spring的特性之一,IOC(控制反转),因为有了IOC,所以我们都不需要自己new对象了,想要什么,spring就给什么.而今天要学习spring的第二个重点,AOP.一篇讲解不完,所以 ...

  2. Spring 的AOP底层实现技术:JDK和CGLIB动态代理

    Spring 的AOP实现技术之JDK的动态代理技术实例: 接口:IUserService (Spring的AOP是动态AOP,实现技术:JDK提供的动态代理和cglib代理,cglib它可以为没有实 ...

  3. Spring AOP学习笔记01:AOP概述

    1. AOP概述 软件开发一直在寻求更加高效.更易维护甚至更易扩展的方式.为了提高开发效率,我们对开发使用的语言进行抽象,走过了从汇编时代到现在各种高级语言繁盛之时期:为了便于维护和扩展,我们对某些相 ...

  4. Spring技术内幕总结 - AOP概述

    AOP是Aspect-Oriented Programming(面向方面/切面编程)的简称.Aspect是一种新的模块化机制,用来描述分散在对象.类或函数中的横切关注点.分离关注点使解决特定领域问题的 ...

  5. Spring框架的核心功能之AOP概述

    1. 什么是AOP的技术? * 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程 * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构 ...

  6. Spring之二:Spring AOP概述

    一.AOP概念回顾 AOP是Aspect-Oriented Programming(面向方面编程)的简称, 虽然可以利用面向对象的方法可以很好地组织代码,也可以通过继承关系实现代码重用,但是程序中总是 ...

  7. Spring源码剖析6:Spring AOP概述

    原文出处: 五月的仓颉 我们为什么要使用 AOP 前言 一年半前写了一篇文章Spring3:AOP,是当时学习如何使用Spring AOP的时候写的,比较基础.这篇文章最后的推荐以及回复认为我写的对大 ...

  8. Spring:AOP面向切面编程

    AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...

  9. Spring框架第五篇之Spring与AOP

    一.AOP概述 AOP(Aspect Orient Programming),面向切面编程,是面向对象编程OOP的一种补充.面向对象编程是从静态角度考虑程序的结构,而面向切面编程是从动态角度考虑程序运 ...

随机推荐

  1. 【软件工程】Beta版本演示

    团队信息 队名:女生都队 组长博客: 博客链接 成员 学号 史恩泽(组长) 031702122 施金海 031702121 阮君曦 031702116 陈银山 031702137 李季城 031702 ...

  2. LeetCode 10. 正则表达式匹配(Regular Expression Matching)

    题目描述 给定一个字符串 (s) 和一个字符模式 (p).实现支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符. '*' 匹配零个或多个前面的元素. 匹配应该覆盖整个字符串 (s ...

  3. 机器学习 - 案例 - 样本不均衡数据分析 - 信用卡诈骗 ( 标准化处理, 数据不均处理, 交叉验证, 评估, Recall值, 混淆矩阵, 阈值 )

    案例背景 银行评判用户的信用考量规避信用卡诈骗 ▒ 数据 数据共有 31 个特征, 为了安全起见数据已经向了模糊化处理无法读出真实信息目标 其中数据中的 class 特征标识为是否正常用户 (0 代表 ...

  4. centos6 安装docker

    docker 安装要求内核大于3.10 , 而centos6 机器上内核一般是2.6 , 除了升级内核外, 还可以安装低版本的docker , 本文介绍docker 1.7的安装. 机器 环境 [ro ...

  5. js 笔记整理

    Js中for.for-in.forEach以及for-of的用法及特性对比 for-in for...in以任意顺序遍历一个对象的可枚举属性.所以for-in不适合用来迭代一个Array.同时,for ...

  6. Tensorflow 保存模型 & 在java中调用

    本节涉及: 保存TensorFlow 的模型供其他语言使用 java中调用模型并进行预测计算 一.保存TensorFlow 的模型供其他语言使用 如果用户选择“y” ,则执行下面的步骤: 判断程序执行 ...

  7. java发送邮件(一)--补充添加附件

    今天来记录一下如何使用java来发送邮件 背景 之前项目有个需求,当产品出现故障时会把情况上送给服务器,服务器发送邮件将故障产品的位置以及故障信息等告知维修人员.发送邮件的接口不是我负责的,但是有兴趣 ...

  8. 奥比中光Astra Pro的使用(1)

    在ubuntu上的使用 首先下载SDK以及OpenNI安装包,下载地址: 解压两个安装包 切换目录到AstraSDK-Linux下的install目录,并输入命令:sudo sh ./install. ...

  9. Redis基础与持久化

    Redis介绍 软件说明 Redis是一款开源的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSQL数据库产品. Redis采用内存(In-Memory)数据集(Dat ...

  10. 17.Azkaban实战

    首先创建一个command.job文件 #command.job type=command command=echo it18zhang 然后打成zip压缩包 上传刚刚打包的zip包 上传完后可以执行 ...