AOP详解

AOP:面向切面编程,AOP是一种编程思想,和语言无关。

拦截器和AOP之间的关系?

拦截器的拦截粒度比较粗,而SpringAOP拦截粒度更细

什么是AOP

AOP称为面向切面编程,在系统开发中主要用来解决一些系统层面上的问题,比如:日志,权限,事务等等。
AOP利用一种称为“横切”的技术,将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证,日志,事务。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

使用场景及作用

对以上统一业务来说,常见的切面业务如:

  1. 响应统一的数据格式
  2. 统一异常处理
  3. 统一日志记录,如跟踪用户访问信息
  4. 用户统一会话管理,权限管理
  5. 方法执行时间计算
  6. 事务管理
  7. 其他

对于使用AOP技术来说,解决的最大问题就是对横切业务的统一管理:

  1. 横切代码的高度复用,和业务代码互相独立,满足代码设计上的高内聚低耦合
  2. 系统更好的扩展性,可维护性

我们学习Spring框架中的AOP,主要基于两种方式:JDK及CGLIB的方式。这两种方式的代理目标都是被代理类中的方法,在运行期,动态的织入字节码生成代理类。

JDK实现

JDK实现时,先通过实现InvocationHandler接口创建方法调用处理器,再通过Proxy来创建代理类。

JDK和CGLIB实现的区别

  1. JDK实现,要求被代理类必须实现接口,之后是通过InvocationHandler及Proxy,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
  2. CGLIB实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。

Spring AOP大部分可以通过CGLIB来实现动态代理,当一个类是final class 的时候就必须使用JDK Porxy来实现动态代理了,因为final class无法被继承。

Spring AOP中的实现

一个类的重要组成部分有两个:

  1. 属性
  2. 方法

SpringAOP只能实现方法拦截,不能实现属性拦截。但是对于AOP来说,AOP是既可以实现属性拦截又可以实现方法拦截的。
SpringAOP支持JDK和CGLIB的方式实现动态代理。默认情况下,实现了接口的类,使用AOP会基于JDK生成代理类,没有实现接口的类,会基于CGLIB生成代理类。

SpringAOP的AspectJ支持

SpringAOP只提供了AspectJ的注解语法支持没有真实使用AspectJ的编译器,在运行时还是基于单纯的AOP。也就是说,加入spring-aspects依赖包,只是可以使用AspectJ的语法,运行时还是基于spring-aop依赖包的动态代理实现。

AOP术语

和大多数技术一样,AOP已经形成了自己的术语。描述切面的常用术语有:通知(Advice),切点(Pointcut)连接点(Joinpoint)

切面

切面(Aspect):由切点和通知组成,它既包含了横切逻辑的定义,也包括了连接点的定义。

连接点

连接点:连接点是在应用执行过程中能够插入切面(Aspect)的一个点。

切点

切点:切点是指通知(Advice)所要织入(Weaving)的具体位置。(切点一定是连接点,连接点不一定是切点,只有程序执行的连接点才是切点)
打个比方:环形高速公路的所有出入口就叫做连接点。而某个我需要进,出的入口,出口才叫切点。

切点表达式说明

@AspectJ支持三种通配符
在这里插入图片描述
:匹配任意字符,只匹配一个元素(包,类,方法,方法参数)
在这里插入图片描述
:匹配任意字符,可以匹配多个元素,在表示类时,必须和*联合使用
在这里插入图片描述
:表示按照类型匹配指定类的所有类,必须跟在类名后面,如com.cad.car+,表示匹配该类的所有子类·包括本身
切点表达式由切点函数组成,其中execution()是最常用的切点函数,用来匹配方法。

切点表达式示例

execution(com.cad.demo.User.(…)):匹配User类里的所有方法
execution(com.cad.demo.User+.(…)):匹配该类的子类包括该类的所有方法
execution(com.cad..(…)):匹配com.cad包下的所有类的所有方法
execution(com.cad….
(…)):匹配com.cad包下,子孙包下所有类的所有方法
execution(*addUser(String,int)):匹配addUser方法,且第一个参数类型是String,第二个参数类型是int
通知(Advice):切面也是有目标(它必须完成的工作)的,在AOP术语中,切面的工作被称之为通知。

通知(Advice)

通知(Advice):切面也是有目标(它必须完成的工作)的,在AOP术语中,切面的工作被称之为通知。
通知:定义了切面是什么,何时使用,其描述了切面切面要完成的工作,还解决何时执行这个工作的问题。
Spring切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用。

  • 前置通知
    使用@Before:通知方法会在目标方法调用之前执行

  • 后置通知
    使用@After:通知方法会在目标方法返回或者抛出异常后调用

  • 返回之后通知
    使用@AfterReturing:通知方法会在目标方法返回后调用

  • 抛异常后通知
    使用@AfterThrowing:通知方法会在目标方法抛出异常后调用

  • 环绕通知
    使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为

许多AOP框架,包括Spring AOP,会将Advice模拟为一个拦截器(Interceptor),并且在JoinPoint上维护多个Advice,进行层层拦截。如之前我们在SpringMVC中学习的@ControllerAdvice就是。

织入(Weaving)

织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。

  • 编译期:

切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。

  • 类加载器

切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),、它可以在目标类被引入应用之前增强该目标类的字节码。ASpectJ5的加载时织入,就支持以这种方式织入切面。

  • 运行期:
    切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。

目标对象(Target Object)

一个或者多个切面所通知(Advice)的对象,也把他叫做被通知的对象(Advised)。既然SpringAOP是通过运行时代理实现的,那么这个对象永远是一个被代理(Proxied)的对象。

SpringAOP的实现举例:

第一步:引入依赖

在这里插入图片描述

第二步:定义切面

在这里插入图片描述

第三步:添加通知

在这里插入图片描述

  1. 首先创建一个controller用于测试
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/login")
    public int login(String username,String password){
        System.out.println("执行了login方法");
        return 0;
    }
    @RequestMapping("/register")
    public int register(String username,String password){
        System.out.println("执行了register方法");
        return 1;
    }
}
  1. 再创建一个UserPointCut类
@Aspect//这个注解表示当前的类是一个切面
@Component//保证Spring启动之后,能够将当前的类加载到框架当中,加载到框架当中才能去用
public class UserPointCut {
    //1.定义切面的规则,使用注解定义规则
    @Pointcut("execution(* com.example.demo.controller.*Controller.*(..))")//表示对所有的Controller下的所有方法都会进行拦截
    public void pointcut(){

    }
    //2.添加通知
    @Before("pointcut()")//把切面的方法名写进去
    public void doBefore(){
        System.out.println("执行了前置通知");
    }
    @After("pointcut()")//把切面的方法名写进去
    public void doAfter(){
        System.out.println("执行了后置通知");
    }
    @AfterReturning("pointcut()")//把切面的方法名写进去
    public void doReturing(){
        System.out.println("执行了返回之后通知的方法");
    }
    @AfterThrowing("pointcut()")//把切面的方法名写进去
    public void doThrowing(){
        System.out.println("执行了抛出异常之后通知的方法");
    }
    @Around("pointcut()")//把切面的方法名写进去,环绕通知
    public Object doAround(ProceedingJoinPoint joinPoint){
        System.out.println("进入了环绕通知:方法执行之前");
        Object result = null;
        try {
            result = joinPoint.proceed();//表示执行被代理的方法,当调用了这个方法才有“执行了register”方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("执行了环绕通知:执行了方法调用之后");
        return 0;
    }
}
  1. 执行结果:
    输入url
    在这里插入图片描述
    浏览器中的得到返回值:1
    idea控制台得到:
    在这里插入图片描述

可以看出这些先后执行顺序。
如果Around通知变成这样:

@Around("pointcut()")//把切面的方法名写进去,环绕通知
    public Object doAround(ProceedingJoinPoint joinPoint){
        System.out.println("进入了环绕通知:方法执行之前");
        Object result = null;
        try {
            //result = joinPoint.proceed();//表示执行被代理的方法,当调用了这个方法才有“执行了register”方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("执行了环绕通知:执行了方法调用之后");
        return 0;
    }

再次输入url:
在这里插入图片描述
浏览器得到:0
idea控制台会得到:
在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)是Spring框架中的一个模块,用于提供横切关注点(Cross-Cutting Concerns)的支持。横切关注点是与应用程序的核心业务逻辑无关的功能,例如日志记录、性能统计、事务管理等。 在Spring AOP中,通过定义切面(Aspect)来捕获横切关注点,并将其应用到目标对象的方法中。切面由切点(Pointcut)和通知(Advice)组成。切点定义了在何处应用通知,通知则定义了在切点处执行的操作。 Spring AOP支持以下几种类型的通知: 1. 前置通知(Before Advice):在目标方法执行之前执行的通知。 2. 后置通知(After Advice):在目标方法执行之后执行的通知,不管方法是否抛出异常。 3. 返回通知(After Returning Advice):在目标方法成功执行并返回结果后执行的通知。 4. 异常通知(After Throwing Advice):在目标方法抛出异常后执行的通知。 5. 环绕通知(Around Advice):围绕目标方法执行的通知,可以在方法调用前后执行自定义操作。 除了通知,Spring AOP还支持引入(Introduction)和切点表达式(Pointcut Expression)等功能。引入允许为目标对象添加新的接口和实现,而切点表达式则允许开发人员定义切点的匹配规则。 要在Spring应用程序中使用AOP,需要进行以下步骤: 1. 引入Spring AOP依赖。 2. 配置AOP代理。 3. 定义切面和通知。 4. 配置切点和通知之间的关系。 总之,Spring AOP提供了一种便捷的方式来处理横切关注点,使得开发人员可以将关注点与核心业务逻辑分离,提高代码的可维护性和可重用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值