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. Java如何接收前端传来的多层嵌套的复杂json串

    想看问题直接解决方式,直接拉到博文底部. Spring的controller在接收前端传参的时候如果参数使用@RequestBody标注的时候 @RequestBody 则会把前端参数转为JSON的形 ...

  2. jsp页面,使用Struts2标签,传递和获取Action类里的参数,注意事项。<s:a action><s:iterator><s:param>ognl表达式

    在编写SSH2项目的时候,除了使用<s:form>表单标签向Action类跳转并传递参数之外,很更多时候还需要用到<s:a action="XXX.action" ...

  3. Python 串口通讯

    摘要: pyserial module: https://github.com/tbusf/pyserial Python使用pyserial进行串口通信:http://blog.csdn.net/l ...

  4. Process.Net

    ProcessSharp的构造函数,对应的测试是 https://github.com/lolp1/Process.NET/blob/master/test/Process.NET.Test/Core ...

  5. 查一张表占多少空间Bytes

    SELECT SUM(BYTES)/1024/1024||'MB' 占用空间 FROM dba_segments WHERE segment_name = '表名' AND owner = '用户名' ...

  6. Android Dalvik、ART及APK编译过程

    0.1 先对Dalvik以及ART做简单介绍: 什么是Dalvik: Dalvik是Google公司自己设计用于Android平台的Java虚拟机.dex格式是专为Dalvik应用设计的一种压缩格式, ...

  7. [转]Nginx配置信息详解

    序言 Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的.从2004年发布至今,凭借开源的力量,已经接近成熟与完善. Nginx功能丰富,可作为HTTP服务器,也 ...

  8. python之scrapy模块logging日志

    1.知识点 """ logging : scrapy: settings中设置LOG_LEVEL="WARNING" settings中设置LOG_F ...

  9. [转]Java Jacob操作Excel

    Jacob项目:https://sourceforge.net/projects/jacob-project/ 转自:https://blog.csdn.net/ZY_extreme/article/ ...

  10. maven项目pom.xml中使用不同源的jar/自定义仓库地址

    笔者本地使用aliyun的maven仓库,在github上找了一个jar,他需求使用第三方仓库. 比如要使用https://jitpack.io上面com.github.navinilavarasan ...