![Spring 5企业级开发实战](https://wfqqreader-1252317822.image.myqcloud.com/cover/807/26542807/b_26542807.jpg)
3.4 基于Spring AOP的实战
3.4.1 增强类型
AOP联盟为增强定义了org.aopalliance.aop.Advice接口,Spring支持5种类型的增强。本章3.3节中使用到的@Before、@After等注解是基于AspectJ实现的增强类型。其实Spring也支持很多增强类型,Spring AOP按照增强在目标类方法中的连接点位置可以分为5种。
• 前置增强:表示在目标方法执行前实施增强。
• 后置增强:表示在目标方法执行后实施增强。
• 环绕增强:表示在目标方法执行前后实施增强。
• 异常抛出增强:表示在目标方法抛出异常后实施增强。
• 引介增强:表示在目标类中添加一些新的方法和属性。
以下将依次介绍每种增量类型,由于基于XML和基于注解的配置其本质都是相同的,因此下面将只通过注解的方式演示Spring各种增强类型,并观察各种增强类型的执行时序。
3.4.2 前置增强
Spring的前置增强主要接口是MethodBeforeAdvice,其顶级接口是AOP联盟中的Advice接口。从如图3-6所示的类图可以发现,Spring的前置增强扩展了Advice接口。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P86_94677.jpg?sign=1739124866-8wiI0tuxTMKYkFme2vjWgUumvkYunaW0-0-7c008998ddfe705278e57ea14a73c2c4)
图3-6 MethodBeforeAdvice相关类图
下面将通过实现MethodBeforeAdvice接口来新增一个前置增强实现类,然后通过案例阐述使用Spring的前置增强类型的编程方式。前置增强实现类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P86_94675.jpg?sign=1739124866-Y0aTu9ExbrDkSd5ZOsJ8Iac3kmXQRyd6-0-66a7ee7ea161e25b63841eda60da5217)
下面将创建一个被增强类Waiter,用于被SpringBeforeAdvice类增强,Waiter类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P86_94676.jpg?sign=1739124866-GhtZGvAckWv9GHFoH5Huk4UTqd7rw4ce-0-283dfb3ed7234c92e6521526759e6b0a)
测试代码中需要创建被代理对象和前置增强的对象,并通过Spring生成代理对象,测试代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P87_94679.jpg?sign=1739124866-snA4xPTI3kRIllPJxlqpqwcKWN4TWvg3-0-9372e7e75291e2b1d23d44370f7fe7d1)
ProxyFactory生成的代理对象proxy就是被增强后的对象,运行测试代码,得到的运行结果如图3-7所示。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P88_29622.jpg?sign=1739124866-hTTvuUa3mj8auDxtgrpzzU0qWoF93noW-0-c04cdd91fd1030241da9a008724b8616)
图3-7 前置增强测试效果图
由测试结果可以看出,在Waiter类的serve方法执行之前,前置增强的逻辑执行了。前置增强即在目标方法执行前实施增强逻辑。
3.4.3 后置增强
Spring的后置增强主要接口是AfterReturningAdvice,其类图如图3-6所示。
下面将通过实现AfterReturningAdvice接口来新增一个后置增强实现类,然后通过3.4.2节中的Waiter案例阐述使用Spring的后置增强类型的编程方式。后置增强实现类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P88_94680.jpg?sign=1739124866-KM7LQQUA9gSqTj2HHWGPqIyT8jfT6nJf-0-899a2dbedb7c40740321a3dec628c9b2)
测试代码中只需修改一行代码:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P88_94681.jpg?sign=1739124866-zgoJethoZ5CXh2sDgcbk9pJ9nSfDfHwn-0-6c8463c5ed721bb453a0952467180edb)
测试结果如图3-8所示。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P89_29771.jpg?sign=1739124866-siHrqVwFqrTx9e6GX414LqW9TOiCJl3z-0-1a286eb930ff769b04d336d5fab1b13d)
图3-8 后置增强测试效果图
3.4.4 环绕增强
Spring的环绕增强主要接口是MethodInterceptor,其类图如图3-6所示。
下面将通过实现MethodInterceptor接口来新增一个环绕增强实现类,然后通过3.4.2节中的Waiter案例阐述使用Spring环绕增强类型的编程方式。环绕增强实现类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P89_94683.jpg?sign=1739124866-Vuq49445IYg64OPJ4Pj5Jsz0fpwPTCyu-0-60a14996b7184a0449748e9252f24f84)
测试代码只需要修改使用环绕增强实现类SpringMethodInterceptor,测试结果如图3-9所示。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P89_29892.jpg?sign=1739124866-JiYmDyspAcIbkZvrqaT8pLJoIsTNs19N-0-2267e289e5a076361a571e2383bb2e7d)
图3-9 环绕增强测试效果图
3.4.5 异常抛出增强
Spring的异常抛出增强主要接口是ThrowsAdvice,其类图如图3-6所示。
下面将通过实现ThrowsAdvice接口来新增一个异常抛出增强实现类,然后通过3.4.2节中的Waiter案例阐述使用Spring的异常抛出增强类型的编程方式。异常抛出增强实现类的代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P90_94684.jpg?sign=1739124866-XyK7zujD4mKO5USC9lXdtIgRBPIcGnzN-0-a860c5109ec1162749b3af73f9493240)
异常抛出增强的测试代码执行效果如图3-10所示。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P90_29978.jpg?sign=1739124866-r8v98Ary7VXQ6gp5i8QkRYijSZnWu8hz-0-0c721bb83310cf3a19e43e33acb3683b)
图3-10 异常抛出增强测试效果图
3.4.6 引介增强
引介增强的目标是在目标类中添加一些新的方法和属性。以Waiter类为例,现在想给其添加一个Management接口中的manage()方法而不修改Waiter类的代码。Management代码如下所示:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P90_94685.jpg?sign=1739124866-WGZT6aBPC0q11zrqpJwt2tRpMCRHOVla-0-144d7c22397c4b5f7a8a89f331c332a4)
Spring的引介增强主要接口是IntroductionInterceptor,通过图3-11可以看出,Spring已经提供了IntroductionInterceptor接口的实现类DelegatingIntroductionInterceptor。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P91_94690.jpg?sign=1739124866-6VDpwrQyc4M7Cw06yxPe3GD1qgr6ec9T-0-f33a38a2792b5bc1e24fb1ec846af2fe)
图3-11 IntroductionInterceptor相关类图
下面将通过扩展DelegatingIntroductionInterceptor来实现引介增强。通过Manager类继承DelegatingIntroductionInterceptor并实现Management接口,Manager代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P91_94687.jpg?sign=1739124866-m6Jxep5gDzJnUxdFKXfsGwRI1gw5DR1m-0-786a754aeb2cef1964ec19e32f68e2d5)
此时需要修改配置文件,需要指定引介增强所在的实现接口并需要将proxyTargetClass属性设置为true。具体配置文件如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P91_94688.jpg?sign=1739124866-VXiWBEs9LYOFVf0B2i7SsQJaPsjr6Isk-0-b6a01001601eb860f446534bc3105af6)
测试代码中,从Spring上下文中获取代理对象waiterProxy,将其强制转化为一个Management对象。修改后测试代码如下:
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P92_94692.jpg?sign=1739124866-iT1msThCLDuVgfRpG8SI0ln1tksltzpT-0-e4fbdca07158d89ba666b25dc111775a)
运行测试结果如图3-12所示,发现Waiter类的代理对象多了一个新的功能,可以调用Management接口的manage方法。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P92_30313.jpg?sign=1739124866-uKNzWnxCPiRSKgXm0DFALuygQenQMSQE-0-17b19a87219d17c22139f502a3c3ab95)
图3-12 引介增强测试效果图
3.4.7 切入点类型
如3.2.2节所述,切入点是匹配连接点的拦截规则。之前的案例中使用的是注解@Pointcut,该注解是AspectJ中的。除了这个注解之外,Spring也提供了其他一些切入点类型:
• 静态方法切入点StaticMethodMatcherPointcut
• 动态方法切入点DynamicMethodMatcherPointcut
• 注解切入点AnnotationMatchingPointcut
• 表达式切入点ExpressionPointcut
• 流程切入点ControlFlowPointcut
• 复合切入点ComposablePointcut
• 标准切入点TruePointcut
各种切入点的类图如图3-13所示。
![](https://epubservercos.yuewen.com/45D01C/15056703904176006/epubprivate/OEBPS/Images/Figure-P93_30327.jpg?sign=1739124866-4yKBZZWL0mLtFOLbFm1bHOarP0TOrA9j-0-f5b92215d2b2b8de15f3adc4314cc750)
图3-13 切入点各类的类图