spring--aop--02--纯注解实现

一、实现aop的三步:

  1. 创建目标类与切面类,加入到Spring容器中,并指明切面类
  2. 在切面类方法上标注通知注解
  3. 开启注解版aop模式

二、配置类实现AOP代码

(1)配置类

package com.fuping3.aopconfig;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = {"com.fuping3.aopconfig"})
/**
 * @EnableAspectJAutoProxy 表示开启注解版aop的注解
 * 备注:
 * 1、proxyTargetClass默认为false--表示使用jdk代理
 * 2、proxyTargetClass = true表示使用cglib代理,当jdk代理不可用时仍使用cglib代理
 */
//
//@EnableAspectJAutoProxy
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class MyAopConfig {
}

(2)Java代码

package com.fuping3.aopconfig;

public interface IUser {
    int div(int i, int j);
}




package com.fuping3.aopconfig;

import org.springframework.stereotype.Component;

@Component
public class User implements IUser{
    public int  div(int i,int j){
        System.out.println("目标方法执行...");
        return i/j;
    }
}




package com.fuping3.aopconfig;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(2)
public class Proxy2 {
    @Before(value = "execution(* com.fuping3.aopconfig.User.div(..))")
    public void proxyBefore(){
        System.out.println("------beforeProxy2.....");
    }
}







package com.fuping3.aopconfig;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
@Component
@Aspect //指明这是一个切面类
@Order(1) //有多个切面类时,使用Order注解指明优先级,数字越小优先级越高
public class UserProxy {
    /**
     * 将公共的切入点表达式抽取为公共的,使用@Pointcut注解
     */
    @Pointcut(value = "execution(* com.fuping3.aopconfig.User.div(..))")
    public void pointDemo(){}

    @Before("pointDemo()")
    public void beforeDiv(){
        System.out.println("--------beforeDiv...");
    }

    /**
     * 后置通知(最终通知)--方法正常执行、异常执行都会执行,类似finally
     */
    @After("pointDemo()")
    public void afterDiv(){
        System.out.println("--------afterDiv...");
    }

    /**
     * 环绕通知--方法执行前后都执行,包括异常时
     * @param joinPoint
     * @return
     */
    @Around(value = "pointDemo()")
    public Object  aroundDiv(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("----------anno around div before...");
        System.out.println("方法名称:"+joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        System.out.println("参数列表"+ Arrays.toString(args));
        Object obj;
        obj=joinPoint.proceed();
/*        try {
            obj=joinPoint.proceed();
        } catch (Throwable e) {
            obj=null;
            System.out.println("方法执行异常"+e);
        }*/

        System.out.println("anno around div after...");
        return obj;
    }

    /**
     * 返回通知--方法返回后进行的增强--方法正常执行会执行,异常执行不会执行
     * returning给被增强方法返回值取个名字,给后面引用
     *
     * 备注:
     * 1、@AfterReturning如果和@Around一起使用,那么就需要给@Around的方法设置返回参数,因为@AfterReturning接收到的值其实是@Around返回的。
     * 2、@AfterReturning如果和@Around一起使用,若@Around中obj=joinPoint.proceed();使用try...catch捕获处理了异常,则有异常时:
     *      (a)该方法还是执行;
     *      并且
     *      (b)会导致@AfterThrowing增强不执行
     * JoinPoint必须为第一个参数
     * @param
     * @param result
     */
    @AfterReturning(value ="pointDemo()",returning="result")
    public void afterReturningDiv(JoinPoint joinPoint,Object result){
        System.out.println("-----------anno afterReturning div...");
        System.out.println("方法名称:"+joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        System.out.println("参数列表"+ Arrays.toString(args));
        System.out.println("返回值:"+result);
    }

    /**
     * 异常增强--有异常时执行的增强
     * throwing用于指定异常的参数名
     * @param joinPoint
     * @param exception
     */
    @AfterThrowing(value ="pointDemo()",throwing="exception")
    public void afterDiv(JoinPoint joinPoint,Exception exception){
        System.out.println("------------anno afterThrowing div...");
        System.out.println("方法名称:"+joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        System.out.println("参数列表"+ Arrays.toString(args));
        System.out.println("异常值:"+exception);
    }
}

(3)测试代码

package com.fuping3.aopconfig;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Client {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(MyAopConfig.class);
        IUser user= (IUser) context.getBean("user");
        Object userProxy = context.getBean(UserProxy.class);
        user.div(10,0);
        System.out.println(user.getClass());
        System.out.println(userProxy.getClass());
    }

}

(4)输出结果

----------anno around div before...
方法名称:div
参数列表[10, 0]
--------beforeDiv...
------beforeProxy2.....
目标方法执行...
--------afterDiv...
------------anno afterThrowing div...
方法名称:div
参数列表[10, 0]
异常值:java.lang.ArithmeticException: / by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.fuping3.aopconfig.User.div(User.java:9)
	at com.fuping3.aopconfig.User$$FastClassBySpringCGLIB$$12d07ebe.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)