一、什么是AOP。
AOP(Aspect Orient Programming),也就是面向切面编程。可以这样理解,面向对象编程(OOP)是从静态角度考虑程序结构,面向切面编程(AOP)是从动态角度考虑程序运行过程。
二、AOP的作用。
常常通过 AOP来处理一些具有横切性质的系统性服务,如事物管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。
三、AOP的实现原理。
如图:AOP 实际上是由目标类的代理类实现的。AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异,AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法。
四、Spring中对 AOP的支持
Spring中 AOP代理由 Spring的 IoC容器负责生成、管理,其依赖关系也由 IoC容器负责管理。因此,AOP代理可以直接使用容器中的其他 Bean实例作为目标,这种关系可由 IoC容器的依赖注入提供。Spring默认使用 Java动态代理来创建 AOP代理,这样就可以为任何接口实例创建代理了。当需要代理的类不是代理接口的时候, Spring自动会切换为使用 CGLIB代理,也可强制使用CGLIB。
AOP编程其实是很简单的事情。纵观AOP编程,其中需要程序员参与的只有三个部分:
- 定义普通业务组件。
- 定义切入点,一个切入点可能横切多个业务组件。
- 定义增强处理,增强处理就是在 AOP框架为普通业务组件织入的处理动作。
所以进行 AOP编程的关键就是定义切入点和定义增强处理。一旦定义了合适的切入点和增强处理,AOP框架将会自动生成 AOP代理,即:代理对象的方法 =增强处理 +被代理对象的方法。
五、Spring中 AOP的实现。
Spring有如下两种选择来定义切入点和增强处理。
- 基于 Annotation的“零配置”方式:使用@Aspect、@Pointcut等 Annotation 来标注切入点和增强处理。
- 基于 XML配置文件的管理方式:使用 Spring配置文件来定义切入点和增强点。
1、基于 Annotation的“零配置”方式。
(1)、首先启用 Spring对 @AspectJ切面配置的支持。
<span style="font-size:18px;">1. <?xml version="1.0" encoding="UTF-8"?>
2. <beans xmlns="http://www.springframework.org/schema/beans"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xmlns:aop="http://www.springframework.org/schema/aop"
5. xsi:schemaLocation="http://www.springframework.org/schema/beans
6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
7. http://www.springframework.org/schema/aop
8. http://www.springframework.org/schema/beans/spring-aop-3.0.xsd">
9. <!-- 启动对@AspectJ注解的支持 -->
10. <aop:aspectj-autoproxy/>
11. </beans>
</span>
如果不打算使用Spring 的 XML Schema 配置方式,则应该在 Spring 配置文件中增加如下片段来启用@AspectJ 支持。
12. <!-- 启用@AspectJ 支持 -->
<bean class="org.springframeword.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
(2)、定义切面 Bean。
当启动了@AspectJ支持后,只要在 Spring容器中配置一个带@Aspect注释的 Bean,Spring将会自动识别该 Bean并作为切面处理。
14. // 使用@Aspect 定义一个切面类
15. @Aspect
16. public class LogAspect {
17. // 定义该类的其他内容
18. ...
19. }
(3)、定义 Before增强处理。
20. // 定义一个切面
21. @Aspect
22. public class BeforeAdviceTest {
23. // 匹配 com.wicresoft.app.service.impl 包下所有类的所有方法作为切入点
24. @Before("execution(* com.wicresoft.app.service.impl.*.*(..))")
25. public void authorith(){
26. System.out.println("模拟进行权限检查。");
27. }
28. }
上面使用@Before Annotation时,直接指定了切入点表达式,指定匹配 com.wicresoft.app.service.impl包下所有类的所有方法执行作为切入点。
关于这个表达式的规则如下图。
( 4 )、定义 AfterReturning 增强处理。
29. // 定义一个切面
30. @Aspect
31. public class AfterReturningAdviceTest {
32. // 匹配 com.wicresoft.app.service.impl 包下所有类的所有方法作为切入点
33. @AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
34. public void log(Object rvt) {
35. System.out.println("模拟目标方法返回值:" + rvt);
36. System.out.println("模拟记录日志功能...");
37. }
}
( 5 )、定义 AfterThrowing 增强处理。
39. // 定义一个切面
40. @Aspect
41. public class AfterThrowingAdviceTest {
42. // 匹配 com.wicresoft.app.service.impl 包下所有类的所有方法作为切入点
43. @AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
44. public void doRecoverActions(Throwable ex) {
45. System.out.println("目标方法中抛出的异常:" + ex);
46. System.out.println("模拟抛出异常后的增强处理...");
47. }
}
(6)、定义 After增强处理。
After 增强处理与AfterReturning 增强处理有点相似,但也有区别:
- AfterReturning 增强处理处理只有在目标方法成功完成后才会被织入。
- After增强处理不管目标方法如何结束(保存成功完成和遇到异常中止两种情况),它都会被织入。
49. // 定义一个切面
50. @Aspect
51. public class AfterAdviceTest {
52. // 匹配 com.wicresoft.app.service.impl 包下所有类的所有方法作为切入点
53. @After("execution(* com.wicresoft.app.service.impl.*.*(..))")
54. public void release() {
55. System.out.println("模拟方法结束后的释放资源...");
56. }
}
(7)、Around增强处理
Around 增强处理近似等于 Before增强处理和 AfterReturning增强处理的总和。它可改变执行目标方法的参数值,也可改变目标方法之后的返回值。
58. // 定义一个切面
59. @Aspect
60. public class AroundAdviceTest {
61. // 匹配 com.wicresoft.app.service.impl 包下所有类的所有方法作为切入点
62. @Around("execution(* com.wicresoft.app.service.impl.*.*(..))")
63. public Object processTx(ProceedingJoinPoint jp) throws java.lang.Throwable {
64. System.out.println("执行目标方法之前,模拟开始事物...");
65. // 执行目标方法,并保存目标方法执行后的返回值
66. Object rvt = jp.proceed(new String[]{"被改变的参数"});
67. System.out.println("执行目标方法之前,模拟结束事物...");
68. return rvt + "新增的内容";
69. }
}
(8)、访问目标方法的参数。
访问目标方法最简单的做法是定义增强处理方法时将第一个参数定义为 JoinPoint类型,当该增强处理方法被调用时,该 JoinPoint参数就代表了织入增强处理的连接点。JoinPoint里包含了如下几个常用方法。
- Object[] getArgs():返回执行目标方法时的参数。
- Signature getSignature():返回被增强的方法的相关信息。
- Object getTarget():返回被织入增强处理的目标对象。
- Object getThis():返回 AOP框架为目标对象生成的代理对象。
提示:当时使用Around处理时,我们需要将第一个参数定义为 ProceedingJoinPoint类型,该类型是JoinPoint类型的子类。
(9)、定义切入点。
所谓切入点,其实质就是为一个切入点表达式起一个名称,从而允许在多个增强处理中重用该名称。
Spring 切入点定义包含两个部分:
- 一个切入点表达式。
- 一个包含名字和任意参数的方法签名。
- // 使用@Pointcut Annotation 时指定切入点表达式
- @pointcut("execution * transfer(..)")
- // 使用一个返回值为void,方法体为空的方法来命名切入点
- private void anyOldTransfer(){}
- // 使用上面定义的切入点
- @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")
- public void writeLog(String msg, Object reVal){
- ...
- }
参考:http://blog.csdn.net/a906998248/article/details/7514969