Spring之AOP模块
对动态代理进行规范化就是AOP(Aspect Orient Programming)
AOP基于动态代理,可使用jdk和cglib
Aop:面向切面编程,以切面为核心. 实现业务功能和非业务功能的解耦合
名词解释:切面,织入,连接点,切入点,目标对象,通知
实现AOP使用AspectJ框架.
AspectJ有五中通知,代表五种执行时间点(前三个比较常用)
- 前置通知@Before
- 后置通知@AfterReturning,注解有returning属性
- 环绕通知
- 异常通知
- 最终通知
AspectJ的切入点表达式(掌握): 指定切面加入的位置
execution(访问修饰符 返回值类型 全限定类名 方法名(参数类型) 抛出异常类型)
ex:public void com.service.SomeService.doSome(String) throws Exception
AspectJ的开发环境(掌握)
导入三个jar包
Spring框架aop的实现jar包:spring-aop.jar
aspectj框架对aop的实现jar包:aspectjrt.jar,aspectjweaver.jar
加入新的约束文件:Spring-aop.xsd
实现aop的框架有很多:
- spring框架实现aop,spring使用接口表示切面,使用方式比较笨重.
- AspectJ框架实现aop,AspectJ可以使用注解和xml配置文件实现aop
定义切面类,在切面类中自定义方法(必须是public void)实现切面的功能
- 在类的上面加入@Aspect,表示当前类是切面类
- 在类的自定义方法的上面,加入AspectJ框架中的通知注解
例如@Before(valu="AspectJ框架字节的切入点表达式")
在xml配置文件中,要声明目标类对象,切面类对象,和自动代理生成器< aop:aspectj-autoproxy />,创建代理对象
通知方法可以有参数
JoinPoint:连接点,表示切入点表达式中的每一个方法
如果JoinPoint要用的话,一定是参数列表的第一个参数,否则系统将绑定不到JoinPoint
//切面类 @Aspect public class MyAspect { @Before(value = "execution(* *..SomeServiceImpl.do*(..))") public void Log(JoinPoint jp) { //获取方法的签名,方法的定义 System.out.println("连接点方法的定义:"+jp.getSignature()); //获取连接点方法的参数列表 Object args []=jp.getArgs(); System.out.println("连接点方法参数的个数:"+args.length); System.out.println("记录日志功能"); }
@AfterReturning,在目标方法后执行
属性: 1. value,表示切入点表达式 2. returning,自定义的变量名,表示目标方法的返回值.自定义的变量名需要和通知方法的参数名一样.
后置通知的特点:
- 在目标方法之后执行
- 能够获取目标方法的执行结果,还可以对执行结果修改
1)目标方法返回值是简单类型时(string和java基本数据类型),在通知方法中修改返回值不会影响目标方法的最终结果
2)目标方法返回值是非简单类型时,在通知方法中修改其属性值,能够影响目标方法的执行最终结果 - 不会影响目标方法的执行
@Around 环绕通知
- 在目标方法的前和后都能增强功能
- 能修改目标方法的执行结果
- 能控制目标方法是否执行
参数:ProceedingJoinPoint继承org.aspectj.lang.JoinPoint,表示切入点
返回值:表示目标方法的执行结果
方法myAround就相当于jdk中的invocationHandler中的invoke();
pjp.proceed()就相当于method.invoke();
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("切入点的信息"+pjp.getSignature()); Object args[]=pjp.getArgs(); System.out.println("目标方法(切入点)的参数个数:"+args.length); Object result = null; System.out.println("环绕通知,在目标方法执行之前,加入日志"); result = pjp.proceed(); result="对目标方法的原有返回值进行了修改"; System.out.println("环绕通知,在目标方法执行之后,加入事务"); return result; }
@AfterThrowing:异常通知,目标方法抛出异常时执行的(有些类似catch块中的代码)
对得到的异常信息,可以做处理.发送邮件,短信通知相关人员,处理问题.
把得到的异常记录到数据库,日志文件,以后可以排查错误
属性:
- value,表示切入点表达式
- throwing,自定义的变量,表示目标方法抛出的异常对象,需要和通知方法的参数名一样
特点:
1.不是异常处理程序,只是得到异常的消息
2.可以作为目标方法的监控程序,检查目标方法是否正常执行
@After:最终通知,总是被执行的(有些类似finally中的代码)
程序执行完毕后最后要执行的工作,例如释放数据库的连接池,释放内存
无论目标方法是否抛异常,都会执行.
@Pointcut:管理和定义切入点的,不是通知注解.如果切面有多个通知使用相同的切入点表达式,可以集中定义切入点
使用@Poincut定义的方法名就是切入点的别名
其他通知注解中的value属性可以使用方法名,表示切入点
@Pointcut(value = "execution(* *..SomeServiceImpl.doSome(..))") private void mypt() { //不要代码 } @其他通知(value="mypt()")
在xml配置文件中,,该标签声明自动代理生成器,默认情况使用jdk代理,
将其属性proxy-target-class设置为true即可设置为CGLIB动态代理.
<aop:aspectj-autoproxy proxy-targe />