SpringAOP

什么是AOP

AOP(Aspect Orient Programming) ,直译过来就是 面向切面编程 . AOP 是一种编程思想 , 是面向对象编程 (OOP) 的一种补充. 面向对象编程将程序抽象成各个层次的对象, 而面向切面编程是将程序抽象成各个切面.

为什么需要AOP

想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。

AOP术语

AOP 领域中的特性术语:

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

通过注解声明 5 种通知类型

@Before(前置通知)

  1. 通知方法会在目标方法调用之前执行

@After(最终通知)

  1. 通知方法会在目标方法返回或异常后调用

@AfterReturning(返回通知)

  1. 通知方法会在目标方法返回后调用

@AfterThrowing(异常通知)

  1. 通知方法会在目标方法抛出异常后调用

@Around(环绕通知)

  1. 它将覆盖原有方法,但是允许你通过反射调用原有方法

简单切面Demo

  1. /**
  2. * 切面
  3. * 切入点和通知的抽象
  4. * 定义 切入点 和通知
  5. * 切入点:定义要拦截哪些类的哪些方法
  6. * 通知:定义了拦截之后方法要做什么
  7. */
  8. @Component // 将对象交给IOC容器进行实例化
  9. @Aspect // 声明当前的类是一个切面
  10. public class LogCut {
  11. /**
  12. * 切入点
  13. * 定义要拦截哪些类的哪些方法
  14. * 匹配规则,拦截什么方法
  15. * 定义切入点
  16. *
  17. * @Pointcut("匹配规则") AOP切入点表达式
  18. * 1.执行所有的公共方法
  19. * execution(pulice *(..))
  20. * 2.执行任意的set方法
  21. * execution(* set*(..))
  22. * 3.设置指定包下的任意类的任意方法(指定包: com.yf.service)
  23. * execution(* com.yf.service.*.*(..))
  24. * 4.设置指定包及子包下的任意类的任意方法 (指定包: com.yf.service)
  25. * execution(* com.yf.service..*.*(..))
  26. * 表达式中的第一个*
  27. * 代表的是方法的修饰范围(public,private,protected)
  28. * 如果取值是 *,则表示所有范围
  29. */
  30. @Pointcut("execution(* com.yf.service..*.*(..))")
  31. public void cut() {
  32. }
  33. /**
  34. * 声明前置通知,并将通知运用到指定的切入点上
  35. * 目标类的方法执行前,执行该通知
  36. */
  37. @Before(value = "cut()")
  38. public void before() {
  39. System.out.println("前置通知...");
  40. }
  41. /**
  42. * 声明返回通知,并将通知运用到指定的切入点上
  43. * 目标类的方法无异常执行后,执行该通知
  44. */
  45. @AfterReturning(value = "cut()")
  46. public void afterReturn() {
  47. System.out.println("返回通知...");
  48. }
  49. /**
  50. * 声明异常通知,并将通知运用到指定的切入点上
  51. * 目标类出现异常后,执行该通知
  52. */
  53. @AfterThrowing(value = "cut()")
  54. public void afterThrowing() {
  55. System.out.println("异常通知...");
  56. }
  57. /**
  58. * 声明异常通知,并将通知运用到指定的切入点上
  59. * 目标类执行方法后,有无异常都会执行
  60. */
  61. @After(value = "cut()")
  62. public void after() {
  63. System.out.println("最终通知...");
  64. }
  65. /**
  66. * 声明环绕通知,并将通知应用到指定的切入点上
  67. * 目标类的方法执行前后,都可以通过环绕通知定义的响应的处理
  68. * 需要显示调用的方法,否则无法访问指定的方法 pjp.proceed()
  69. *
  70. * @param pjp
  71. * @return
  72. */
  73. @Around(value = "cut()")
  74. public Object around(ProceedingJoinPoint pjp) {
  75. System.out.println("环绕通知-前置通知...");
  76. Object object = null;
  77. try {
  78. //显示调用对应的方法
  79. object = pjp.proceed();
  80. System.out.println(pjp.getTarget());
  81. System.out.println("环绕通知-返回通知...");
  82. } catch (Throwable e) {
  83. e.printStackTrace();
  84. System.out.println("环绕通知-异常通知...");
  85. }
  86. System.out.println("环绕通知-最终通知...");
  87. return object;
  88. }
  89. }
  1. @Service
  2. public class UserService {
  3. public void test() {
  4. System.out.println("UserService test...");
  5. }
  6. }
  1. public class App {
  2. public static void main(String[] args) {
  3. ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  4. UserService userService = (UserService) context.getBean("userService");
  5. userService.test();
  6. }
  7. }
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. https://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd
  9. http://www.springframework.org/schema/aop
  10. http://www.springframework.org/schema/aop/spring-aop.xsd">
  11. <!-- 开启自动化扫描 -->
  12. <context:component-scan base-package="com.yf"/>
  13. <!-- 配置AOP代理 -->
  14. <aop:aspectj-autoproxy/>
  15. </beans>