Spring的AOP编程-基于注解

AOP需要另外加入的jar包(Idea中)

com.springsource.org.aopalliance-1.0.0.jar   提取码:y5i5

面向切面编程(AOP):在一个工程中,我们想要在执行每一个方法之前打印一串日志,在方法结束后打印一串日志。最笨的方法是在每个方法中去添加这些日志代码,但是这样不仅会影响原本的逻辑代码,还会出现大量的重复代码。AOP可以解决这样的问题,我们可以把每个方法执行前作为一个切面,把它从系统中复制出来,加上日志代码,方法结束同样可以这样做。

AOP中的术语

切面:横切关注点,我们要添加在方法前和方法后的日志方法都在切面中

通知:切面要完成的工作

目标:被通知的对象(原业务逻辑)

代理:通知+目标

连接点:某个方法执行的前后或者抛出异常点或返回点

切点:具体到方法,指定要对哪些方法进行切面编程,通过切点可定位多个连接点

基于AspectJ注解的AOP

1.使用aop命名空间,在xml文件中加入说明,使AspectJ注解起作用,会自动为匹配到的bean创建代理

2.在要声明为切面的类前加上注解@Aspect,另外加上@Component使IOC容器为其生成bean

4.声明切点:由于不同的类型的通知可能使用的是同一个切点,所以可以声明一个方法对切点进行重用。这个方法不需要实现代码,只使用它的方法名。切点的声明:exexution(返回类型+包名+方法名)

/*
    * 定义一个声明切入点表达式的方法
    * 一般该方法中不需要添入其他方法
    * 后面的其他通知使用该方法名引用当前切入点表达式
    * */
    @Pointcut("execution(public int com.ustc.yi.aop.impl.ArithmeticCalculator.*(int,int))")
    public void declareJointPointExpression(){}

3.在切面中加入各种通知,通知以方法的形式存在,在方法前加上各种注解可声明为不同类型的通知

①前置通知(@Before):在目标方法开始之前执行,切点声明在@Before后的括号中(value)

使用JointPoint变量可以来访问连接细节,如方法名和方法使用的变量

 //声明该方法是一个前置通知:在目标方法开始之前执行
    @Before("declareJointPointExpression()")
    public void beforeMethod(JoinPoint joinPoint) {
        //通过连接点获取方法的参数
        System.out.println(joinPoint.getTarget());
        String methodName = joinPoint.getSignature().getName();
        List args = Arrays.asList(joinPoint.getArgs());
        System.out.println("前置通知");
        System.out.println("The method " + methodName + " begins with " + args);
    } 
  

②后置通知(@After):无论方法是否异常都会执行的通知,在后置通知中不能访问目标方法执行的结果(可能方法异常无法正常返回)

//后置通知:在目标方法执行后(无论是否发生异常都会执行),执行的通知
    //在后置通知中还不能访问目标方法执行的结果
    @After("declareJointPointExpression()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("后置通知");
        System.out.println("The method " + methodName + " ends");
    }

③返回通知(@AfterReturning):方法正常结束后执行的通知,可以访问返回值,方法异常时该通知不执行。可以在前面注解中将返回值赋给一个变量result,然后可以获取到返回值

 //在方法正常结束后执行的代码
    //返回通知可以访问方法的返回值

    @AfterReturning(value = "declareJointPointExpression()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("返回通知");
        System.out.println("The method " + methodName + " ends with " + result);
    }

④异常通知(@AfterThrowing):方法异常时执行的通知,可以在注解中指定一个变量获取到发生的异常,另外可以在方法变量中指定发生何种异常时才执行该通知,如下面只有在发生空指针异常时才会执行该通知。

 //目标方法出现异常时执行
    //可以访问到异常对象,可以指定出现特定异常时再执行通知代码
    @AfterThrowing(value = "declareJointPointExpression()", throwing = "ex")
    //指定只有在发生空指针异常时执行
    public void afterReturning(JoinPoint joinPoint, NullPointerException ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("异常通知");
        System.out.println("The method " + methodName + " occurs Exception " + ex);
    }

⑤环绕通知(@Around):环绕通知可以决定方法是否执行,需要携带ProceedingJoinPoint参数,这个参数可以决定方法的执行,在这条执行语句之前的通知即为前置通知,在执行结束后的即为返回通知,发生异常的通知即为异常通知,在最后面的通知为后置通知。

@Around(value = "execution(* *.*(int,int))")
    public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint)  {
        Object result=null;
        String methodName=proceedingJoinPoint.getSignature().getName();

        try {
            //前置通知
            System.out.println("method "+methodName+" begins");
            //执行目标方法
            result=proceedingJoinPoint.proceed();
            //返回通知
            System.out.println("method "+methodName+" returns");
        } catch (Throwable throwable) {
            System.out.println("Exception "+throwable);
            throwable.printStackTrace();
        }
        //后置通知
        System.out.println("method "+methodName+" ends");
        return result;
    }

4.切面的优先级,当有多个切面时,可以用Order(n)注解来确定切面的优先级,n越小优先级越高。

@Order(1)
@Aspect
@Component
public class VlidationAspect {
    @Before(value = "LoggingAspect.declareJointPointExpression()")
    public void VlidationAspect(){
        System.out.println("数据验证");
    }

}

 

你可能感兴趣的:(Spring)