[关闭]
@boothsun 2023-01-29T11:18:21.000000Z 字数 3350 阅读 913

Spring AOP 基础知识

Spring


内容总结自以下优秀博文:
1. 关于 Spring AOP (AspectJ) 你该知晓的一切
2. AspectJ 编译时织入(Compile Time Weaving, CTW)

Spring AOP简介

AOP(Aspect-Oriented Programming),即面向切面编程,它利用一种称为“横切”的技术,将影响了多个类的公共行为封装到一个可重用的模块,并将其命名为“Aspect”(即切面)。所谓“切面”,简单来说就是那些与业务无关,却为多个业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之前的耦合度。

常见的应用场景就是 日志打印收集,权限校验,事务管理,性能监测等公共业务逻辑。这些业务并不是主流程的逻辑,但是确实是不可或缺的逻辑。通常,对于这些代码我们并不希望他们侵入到核心代码逻辑中,更希望他们可以在核心代码逻辑外围,实现自动的执行。

image.png-138.8kB

AOP的核心概念

AOP的术语

  1. 切面(Aspect):就是你想给代码织入的代码判断,如权限处理、日志记录等。
  2. 编程(编织):就是给指定的程序加上额外的业务逻辑的过程,比如将权限验证插入到用户登录的过程。
  3. 通知(Advice):表示是在程序的哪里织入切面,比如前面织入,还是后面织入,或者是在抛出异常的时候织入。
  4. 连接点(Joinpoint):表示给那个程序织入切面,也就是被代理的目标对象的目标方法。
  5. 切点(Pointcut):表示给哪些程序织入切面,是连接点的集合,比如是用户登录和用户查询等都需要织入。

AOP的5种通知类型:

使用 AspectJ实现AOP功能

AspectJ是以一种编译时静态织入的方式来实现AOP功能的,所谓编译时静态织入就是指编译期间字节码文件改写,根据切点规则将通知写到代码的指定位置。AspectJ会要求使用自己的特定编译器编译,然后在编译期间,AspectJ会根据定义的切点规则,将通知代码加到业务代码的前后,所以这种形式在源代码上看上去是隔离开的,但是到了字节码文件时又是堆砌在一起。

AspectJ使用示例

  1. // 1. AuthCheck
  2. @Target(ElementType.METHOD)
  3. @Retention(RetentionPolicy.RUNTIME)
  4. public @interface AuthCheck {
  5. }
  6. // 2. SampleService
  7. package org.opoo.samples.aspectj;
  8. public interface SampleService {
  9. int add(int x, int y);
  10. String getPassword(String username);
  11. }
  12. // 3. SampleServiceImpl
  13. package org.opoo.samples.aspectj;
  14. public class SampleServiceImpl implements SampleService {
  15. public int add(int x, int y) {
  16. return x + y;
  17. }
  18. /**
  19. * 带自定义Annotation的方法。
  20. */
  21. @AuthCheck
  22. public String getPassword(String username) {
  23. return "password";
  24. }
  25. }
  26. // 4. SampleAspect
  27. package org.opoo.samples.aspectj;
  28. import org.aspectj.lang.reflect.MethodSignature;
  29. import java.lang.reflect.Method;
  30. public aspect SampleAspect{
  31. /**
  32. * 切点:SampleService继承树中所有 public 且以 add 开头的方法。SampleServiceImpl#add(int,int)方法满足这个条件。
  33. */
  34. pointcut serviceAddMethods(): execution(public * org.opoo.samples.aspectj.SampleService+.add*(..));
  35. /**
  36. * 切点:SampleService继承树中所有标注了AuthCheck的方法。
  37. */
  38. public pointcut serviceAuthCheckAnnotatedMethods(): execution(* org.opoo.samples.aspectj.SampleService+.*(..)) && @annotation(AuthCheck);
  39. /**
  40. * 通知
  41. */
  42. Object around(): serviceAddMethods(){
  43. Object oldValue = proceed();
  44. System.out.println("原值是:" + oldValue);
  45. return Integer.MIN_VALUE;
  46. }
  47. before(): serviceAuthCheckAnnotatedMethods(){
  48. if(1==1){//权限检查代码
  49. throw new IllegalStateException("权限不足");
  50. }
  51. }
  52. /**
  53. * 切入点:SampleService继承树中所有 public 的方法。
  54. */
  55. public pointcut serviceAllPublicMethods(): execution(public * org.opoo.samples.aspectj.SampleService+.*(..));
  56. after(): serviceAllPublicMethods(){
  57. MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
  58. Method method = methodSignature.getMethod();
  59. System.out.println("[LOG] 方法被调用了: " + method);
  60. }
  61. }
  62. // 运行结果:
  63. 原值是:30
  64. [LOG] 方法被调用了: public int org.opoo.samples.aspectj.SampleServiceImpl.add(int,int)
  65. 现值是:-2147483648
  66. [LOG] 方法被调用了: public java.lang.String org.opoo.samples.aspectj.SampleServiceImpl.getPassword(java.lang.String)

AspectJ原理浅析

AspectJ是一个Java实现的AOP框架,它能够对Java代码进行AOP编译(一般在编译期进行),让Java代码具有AspectJ的AOP功能(当然需要特殊的编译器),可以这样说AspectJ是目前实现AOP框架中最成熟的,功能最丰富的语言,更幸运的是,AspectJ与Java程序完全兼容,几乎是无缝关联,因此对于有Java编程基础的工程师,上手和使用都非常容易。在案例中,我们使用aspect关键字定义了一个类,这个类就是一个切面,它可以是单独的日志切面(功能),也可以是权限切面或者其他,在切面内部使用了pointcut定义了两个切点,一个用于权限验证,一个用于日志记录,而所谓的切点就是那些需要应用切面的方法,如需要在sayHello方法执行前后进行权限验证和日志记录,那么就需要捕捉该方法,而pointcut就是定义这些需要捕捉的方法(常常是不止一个方法的),这些方法也称为目标方法,最后还定义了两个通知,通知就是那些需要在目标方法前后执行的函数,如before()即前置通知在目标方法之前执行,即在sayHello()方法执行前进行权限验证,另一个是after()即后置通知,在sayHello()之后执行,如进行日志记录。到这里也就可以确定,切面就是切点和通知的组合体,组成一个单独的结构供后续使用。

Spring AOP

Spring AOP DEMO

Spring AOP 原理浅析

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注