一、SpringAOP介绍
- AOP(Aspect Oriented Programming):面向切面编程。
- 在不修改源代码的基础上,增加新的功能。
二、SpringAOP的 SchemaBase方式实现
1、流程
- 导入SpringAOP的jar包。
- 在src下创建advice包,并创建前置通知和后置通知类。
前置通知:实现MethodBeforeAdvice接口
后置通知:实现AfterReturning 接口 - 在applicationcontext.xml文件中配置资源,并声明组装规则。
- 从Spring容器中获取代理对象,完成功能开发。
2、概念
- 真实对象:要进行功能扩展的对象
- 代理对象:完成功能扩展的对象
- 切点:要进行功能扩展的方法
- 切面:前置/后置通知+切点
- 前置通知方法:切点之前执行的方法
- 后置通知方法:切点之后执行的方法
- 织入:前置/后置通知+切点,形成切面的过程
3、环绕通知
-
特点:
将扩展代码和调用原有切点方法的代码声明在一起,简化扩展流程。也就说环绕通知中包含了前置通知和后置通知。 -
使用流程:
-
创建一个普通java类,实现环绕通知的接口(MethodInterceptor)。
-
在applicationcontext.xml文件中配置环绕通知的bean。
-
在组装规则中,使用环绕通知的组装。
-
4、异常通知
使用:
- 创建一个普通java类,实现异常接口(ThrowsAdvice)。
- 在applicationcontext.xml文件中配置异常通知的bean。
- 在applicationcontext.xml文件中配置组装规则。
注意:建议将异常通知的配置配置在组装规则的最上面。
三、SpringAOP的SchemaBase方法的参数
1、前置通知
-
Method method:切点的方法对象
-
Object[] objects:代理方法接收的实参的数组
-
Object o:真实对象
2、后置通知
-
Object o:真实方法的返回值
-
Method method:切点的方法对象
-
Object[] objects:代理方法接收的实参的数组
-
Object o:真实对象
3、环绕通知
- MethodInvocation:可以通过get方法获取以上通知的所有参数。
4、异常通知
- Exception ex:获取异常信息
四、SpringAOP的AspectJ方式实现
1、概念:
在一个类中,实现声明所有的通知方法,并在配置文件中的切面配置中,指明哪些方法是前置,哪些是后置即可。
2、使用:
- 创建web项目,并导入jar包。
- 在src下创建MVC包结构。
- 在src下创建并配置applicationcontext.xml文件。
- 切点的bean
- 扩展类的bean
- 配置切面
- 获取Spring容器中的扩展对象,完成功能操作。
五、AspectJ和SchemaBase方式比较
1、相同点
-
都能在不修改源码的情况下,实现功能的扩展。
2、不同点
- SchemaBased方式基于接口来区别前置和后置和环绕和异常通知的,而AspectJ方式是在配置文件中使用标签来区分。
- AspectJ方式切点只在Aop:aspect标签下有效。SchemaBased方式的切点在全局有效。SchemaBased的切点的通用性比AspectJ方式要好。
- 扩展时涉及参数的流程
- AspectJ
①切点方法中声明形参完成数据处理
②修改通知方法声明形参接收对应的实参
③修改配置文件中的切点声明,切点中的方法上声明对应的参数类型。同时还要声明参数的形参名
④在通知的配置上声明参数名- Schema
①在切点方法上声明形参完成功能处理
②在配置文件中修改切点的路径为带有参数的切点
③直接在通知方法中的形参中的Object[]中获取参数使用即可
- Schema
- AspectJ
总结:不涉及到参数问题,使用AspectJ方式。涉及到参数,使用SchemaBased方式。
六、SpringAOP的切点声明格式
- 切点是某包某类的无参数的方法
示例:execution(* com.abc.service.impl.Student.test()) - 切点是某包某类带有参数的方法
示例:execution(* com.abc.service.impl.Student.test(String,int)) - 切点是某包某类的某个同名的所有方法
示例:.. 表示任意个数任意类型的参数----execution(* com.abc.service.impl.Student.test(..)) - 切点是某包下的某类的所有方法
示例:*表示任意的类名,方法名,包名----execution(* com.abc.service.impl.Student.*(..)) - 切点是某包下的所有类的所有方法
示例:* 表示任意的类名,方法名,包名----execution(* com.abc.service.impl.*.*(..))