Spring之AOP模块

剑铭 2019-11-04

对动态代理进行规范化就是AOP(Aspect Orient Programming)

AOP基于动态代理,可使用jdk和cglib

Aop:面向切面编程,以切面为核心. 实现业务功能和非业务功能的解耦合

名词解释:切面,织入,连接点,切入点,目标对象,通知

实现AOP使用AspectJ框架.

AspectJ有五中通知,代表五种执行时间点(前三个比较常用)

  1. 前置通知@Before
  2. 后置通知@AfterReturning,注解有returning属性
  3. 环绕通知
  4. 异常通知
  5. 最终通知

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的框架有很多:

  1. spring框架实现aop,spring使用接口表示切面,使用方式比较笨重.
  2. AspectJ框架实现aop,AspectJ可以使用注解和xml配置文件实现aop

定义切面类,在切面类中自定义方法(必须是public void)实现切面的功能

  1. 在类的上面加入@Aspect,表示当前类是切面类
  2. 在类的自定义方法的上面,加入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. 在目标方法之后执行
  2. 能够获取目标方法的执行结果,还可以对执行结果修改
    1)目标方法返回值是简单类型时(string和java基本数据类型),在通知方法中修改返回值不会影响目标方法的最终结果
    2)目标方法返回值是非简单类型时,在通知方法中修改其属性值,能够影响目标方法的执行最终结果
  3. 不会影响目标方法的执行

@Around 环绕通知

  1. 在目标方法的前和后都能增强功能
  2. 能修改目标方法的执行结果
  3. 能控制目标方法是否执行

参数: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块中的代码)
对得到的异常信息,可以做处理.发送邮件,短信通知相关人员,处理问题.
把得到的异常记录到数据库,日志文件,以后可以排查错误
属性:

  1. value,表示切入点表达式
  2. 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 />

相关推荐