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. Leetcode题目215.数组中的第K个最大元素(中等)

    题目描述: 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 ...

  2. ADB命令指令控制Android系统的WIFI连接开启/关闭状态

    Android系统的usb调试已开启,连接电脑(有ADB环境) 1.在cmd中,进入shell指令模式 adb shell 2.进入ROOT指令模式 su 3. 打开WIFI指令 svc wifi e ...

  3. 本地服务CURL请求本地另一个服务API返回超时/或无返回

    入职之后一直在忙,终于有时间整理一波最近踩到的坑. 起因: 项目是微服务架构,一个项目对外提供API,新的项目调用API获得数据.于是就在本地搭建了两个服务.配置了两个虚拟域名,指向两个项目,当然我本 ...

  4. linux下如何单独编译设备树?

    答: make <vendor>/<device_name>.dtb 如: make freescale/fsl-1043a-rdb.dtb

  5. easyUI之Messager(消息窗口)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  6. 消息队列 RabbitMQ 入门介绍

    来源:http://ityen.com/archives/578 一.什么是RabbitMQ? RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系 ...

  7. Oracle CDC (Change Data Capture)更新数据捕获——Asynchronous HotLog Mode(附带简单的kettle任务实现数据同步)

    Performing Asynchronous HotLog Publishing Step 1   Source Database DBA: Set the database initializat ...

  8. 一百二十:CMS系统之注册功能前后端逻辑

    给提交按钮加一个id,方便写js js //发送ajax请求注册请求$(function () { $('#submit-btn').click(function (event) { event.pr ...

  9. vue3.x版本安装vue-cli建项目

    vue-cli版本在3以上 全局安装vue-cli npm install -g @vue/cli 建立项目工程,假设项目建在e:\vueProject\vue-cli3.0+目录下: 先进入此目录: ...

  10. IDEA的热部署设置方式

    在这里只说一种简单的方式就是在idea中进行简单的设置就可以: 第一步:设置IDEA开启项目自动编译,进入设置找到Build,Execut, Deployment -> Compiler 勾选中 ...