Spring全家桶之Spring核心篇,AspectJ框架基于注解的 AOP 实现

694 阅读8分钟

「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」。

👨‍🎓作者:Java学术趴

🏦仓库:GithubGitee

✏️博客:CSDN掘金InfoQ云+社区

💌公众号:Java学术趴

🚫特别声明:原创不易,未经授权不得转载或抄袭,如需转载可联系小编授权。

🙏版权声明:文章里的部分文字或者图片来自于互联网以及百度百科,如有侵权请尽快联系小编。微信搜索公众号Java学术趴联系小编。

☠️每日毒鸡汤:微笑拥抱每一天,做像向日葵般温暖的女子。

👋大家好!我是你们的老朋友Java学术趴。最近小编又在整了Spring全家桶笔记,笔记会每天定时的进行发放,喜欢的大佬们欢迎收藏点赞关注呦。小编会每天分享的呦。Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

AspectJ 框架

1.1 AspectJ介绍

  • 对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向 切面编程。然而,AspectJ 也实现了 AOP 的功能,且其实现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框 架中。

image.png

在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

  • AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。AspectJ 是Eclipse基金会的一个开源项目

image-20211114143205314

  • a seamless aspect-oriented extension to the Javatm programming language(一种基于 Java 平台 的面向切面编程的语言)
  • Java platform compatible(兼容 Java 平台,可以无缝扩展)
  • easy to learn and use(易学易用)

1.2 AspectJ实现aop的两种方式

  • 使用xml的配置文件:配置全局事务
  • 使用注解,实际开发中用到的就是注解的方式。aspectJ有5个注解。

1.3 AspectJ框架的使用方式

  • 切面的执行时间:这个执行时间在规范中叫做Advice(通知、增强)。在aspectJ框架中使用注解表示。也可以使用xml配置文件中的标签表示。

    • @Before (前置通知)
    • @AfterReturning (后置通知)
    • @Around (环绕通知)
    • @AfterThrowing (异常通知)
    • @After (最终通知)

    以上的五个注解都是表示切面执行的时间。

  • 切面的执行位置: 使用切入点表达式

1.4 AspectJ的通知类型(了解)

AspectJ中常用的五种类型:

  • 前置通知 (@Before)
  • 后置通知 (@AfterReturning)
  • 环绕通知 (@Around)
  • 异常通知 (@AfterThrowing)
  • 最终通知 (@After)

1.5 切入点表达式语法(指定切入点的位置)

AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是:

// 参数之间使用空格分开
execution(modifiers-pattern? ret-type-pattern 
declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
​
// 以上的4个部分,注意这个参数只写参数的类型吗,而不写参数的形参值。
execution(访问权限 方法返回值 包名.类名.方法名称(方法的参数类型) 异常类型)

解释AspectJ参数信息

  • modifiers-pattern :访问权限类型
  • ret-type-pattern : 返回值类型
  • declaring-type-pattern :包名类名
  • name-pattern(param-pattern) : 方法名(参数类型和参数个数)
  • throws-pattern : 抛出异常类型

注意:? 代表可选的部分。也就是上面没有标粗的参数。

切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就 是方法的签名。

1.6 切入点表达式使用同配符

在AspectJ可以使用通配符的目的 :为了可以在配置文件中使用一个注解来获取到多个目标对象,然后给这些目标对象添加统一的功能或者补充其他的功能。

举列说明:(只有返回值类型以及方法名(参数)这两个参数不可以省略,所在在简化的切点表达中肯定存在这两个参数的信息)

  • execution(public * *(..)) : 指定切入点的位置,任意公共的方法。
  • execution(* set*(...)) : 指定切入点的位置,任意一个以 "set" 开始的方法。
  • execution(* com.yunbocheng.service.* .*(..)) : 指定切入点的位置是service包中的任意类中的任意方法。
  • execution(* com.yunbocheng.service..* .(..)): 指定切入点的位置是 service包或者子包中的任意类的任意方法。".."出现在类名中时,后面必须跟"",表示包、子包下的所有类。
  • execution(* ..service. * .(..)): 指定切入点的位置是:多级包下的service子包下所有类(接口)中所有方法为切入点。
  • execution(* .service. * .(..)): 指定切入点的位置是:一级包下的service子包下所有类(接口)中所有方法为切入点。
  • execution(* joke(String,*)) : 指定所有的包中的 joke() 方法,该方法的第一个参数为String,第二个参数可以是任意类型。如:joke(String s1,String s2) 、joke(String s1,double d)
  • execution(* joke(String,..)): 所有的 joke()方法,该方法第一个参数为 String,后面可以有任意个参数且 参数类型不限,如 joke(String s1)、joke(String s1,String s2)和 joke(String s1,double d2,String s3) 都是。

AspectJ 基于注解的 AOP 实现(掌握)

  • 在 AspectJ 实现 AOP 时,要引入 AOP 的约束。配置文件中使用的 AOP 约束中的标签, 均是 AspectJ 框架使用的,而非 Spring 框架本身在实现 AOP 时使用的。
  • AspectJ 对于 AOP 的实现有注解和配置文件两种方式,常用是注解方式。

第一步:定义业务接口与实现类

image-20211115093838676

第二步:定义切面类

类中定义了若干普通方法,将作为不同的通知方法,用来增强功能。

第三步:在spring配置文件(applicationContext.xml)中声明目标对象以及切面类对象

第四步:在spring的配置文件(applicationContext.xml)注册 AspectJ 的自动代理

  • 在定义好切面 Aspect 后,需要通知 Spring 容器,让容器生成“目标类+ 切面”的代理 对象。这个代理是由容器自动生成的。只需要在 Spring 配置文件中注册一个基于 aspectj 的 自动代理生成器,其就会自动扫描到@Aspect 注解,并按通知类型与切入点,将其织入,并 生成代理。

image-20211115094650017

  • 的底层是由 AnnotationAwareAspectJAutoProxyCreator 实现的。 从其类名就可看出,是基于 AspectJ 的注解适配自动代理生成器。
  • 其工作原理是,通过扫描找到@Aspect 定义的切面类,再由切 面类根据切入点找到目标类的目标方法,再由通知类型找到切入的时间点。

第五步:测试类中使用目标对象的 id来进行定位

image-20211115094838802

几种通知的使用方式

3.1 [掌握]@Before 前置通知-方法有 JoinPoint 参数

  • 在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参 数。该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、 目标对象等。

不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该 参数。

  • 前置通知的核心代码,其余代码和以上代码一致。

3.2 [掌握]@AfterReturning 后置通知-注解有 returning 属性

  • 在目标方法执行之后执行。由于是目标方法之后执行,所以可以获取到目标方法的返回值。 该注解的 returning 属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含 JoinPoint 参数外,还可以包含用于接收返回值的变量。该变量最好为 Object 类型,因为目标方法的返回值可能是任何类型。

###3.3 [掌握]@Around 环绕通知-增强方法有 ProceedingJoinPoint 参数

  • 在目标方法执行之前之后执行。被注解为环绕增强的方法要有返回值,Object 类型。并 且方法可以包含一个 ProceedingJoinPoint 类型的参数。接口 ProceedingJoinPoint 其有一个 proceed()方法,用于执行目标方法。若目标方法有返回值,则该方法的返回值就是目标方法 的返回值。最后,环绕增强方法将其返回值返回。该增强方法实际是拦截了目标方法的执行。

###3.4 [了解]@AfterThrowing 异常通知-注解中有 throwing 属性

  • 在目标方法抛出异常后执行。该注解的 throwing 属性用于指定所发生的异常类对象。 当然,被注解为异常通知的方法可以包含一个参数 Throwable,参数名称为 throwing 指定的 名称,表示发生的异常对象。

###3.5 [了解]@After 最终通知

  • 无论目标方法是否抛出异常,该增强均会被执行。

今天就先分享到这里啦,明天小编继续给大家分享Spring全家桶笔记!!

以上项目的源代码,点击星球进行免费获取 星球 (Github地址)如果没有Github的小伙伴儿。可以关注本人微信公众号:Java学术趴,发送Spring,免费给发给大家项目源码,代码是经过小编亲自测试的,绝对可靠。免费拿去使用。