Spring_动态代理_通知的执行顺序


 

 

 

 


一、单切面-普通通知

 目标对象

@Service
public class MyMathCalculator{
	/**
	 * 加法
	 */
	public int add(int i, int j) {
		int result = i + j;
		System.out.println("方法内部执行");
		return result;
	}
	/**
	 * 减法
	 */
	public int sub(int i, int j) {
		int result = i - j;
		System.out.println("方法内部执行");
		return result;
	}
	/**
	 * 乘法
	 */
	public int mul(int i, int j) {
		//方法的兼容性;
		int result = i * j;
		System.out.println("方法内部执行");
		return result;
	}
	/**
	 * 除法
	 */
	public int div(int i, int j) {
		int result = i / j;
		System.out.println("方法内部执行");
		return result;
	}
}
@Aspect
@Component
public class LogUtils {
	/**
	 * @Before:在目标方法之前运行;  					 前置通知
	 * @After:在目标方法结束之后						后置通知
	 * @AfterReturning:在目标方法正常返回之后			返回通知
	 * @AfterThrowing:在目标方法抛出异常之后运行			异常通知
	 * @Around:环绕								环绕通知
	 */
	@Pointcut("execution(public int com.atguigu.impl.MyMathCalculator.*(..))")
	public void hahaMyPoint(){};

    //想在执行目标方法之前运行;写切入点表达式
	@Before("hahaMyPoint()")
	public static void logStart(JoinPoint joinPoint){
		//获取到目标方法运行是使用的参数
		Object[] args = joinPoint.getArgs();
		//获取到方法签名
		Signature signature = joinPoint.getSignature();
		String name = signature.getName();
		System.out.println("[LogUtils-前置]【"+name+"】方法开始执行,用的参数列表【"+Arrays.asList(args)+"】");
	}
    //想在目标方法正常执行完成之后执行
	@AfterReturning(value="hahaMyPoint()",returning="result")
	public static void logReturn(JoinPoint joinPoint,Object result){
		Signature signature = joinPoint.getSignature();
		String name = signature.getName();
		System.out.println("[LogUtils-返回]【"+name+"】方法正常执行完成,计算结果是:"+result);
	}
    //想在目标方法出现异常的时候执行
    @AfterThrowing(value="hahaMyPoint()",throwing="exception")
    public static void logException(JoinPoint joinPoint,Exception exception) {
        System.out.println("[LogUtils-异常]【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
    }

    //想在目标方法结束的时候执行
    @After("hahaMyPoint()")
	private int logEnd(JoinPoint joinPoint) {
		System.out.println("[LogUtils-后置]【"+joinPoint.getSignature().getName()+"】方法最终结束了");
		return 0;
	}
}
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");

@Test
public void test02(){
	MyMathCalculator bean = ioc.getBean(MyMathCalculator.class);
	bean.div(1, 1);
}

没有异常的输出: 

[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 1]】
方法内部执行
[LogUtils-后置]【div】方法最终结束了
[LogUtils-返回]【div】方法正常执行完成,计算结果是:1

异常输出: 

[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 0]】
[LogUtils-后置]【div】方法最终结束了
[LogUtils-异常]【div】方法执行出现异常了,异常信息是【java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查

java.lang.ArithmeticException: / by zero

    at com.atguigu.impl.MyMathCalculator.div(MyMathCalculator.java:39)

 注意:这里的 后置通知(不管方法是否发生异常,都会执行) 都是在,返回通知(目标方法正常完成后被织入)和异常通知(目标方法发生异常后被织入)之前和我们的理解可能有点不同。


二、 单切面-环绕通知

@Aspect
@Component
public class LogUtils {

	@Pointcut("execution(public int com.atguigu.impl.MyMathCalculator.*(..))")
	public void hahaMyPoint(){};

    /**
     * @throws Throwable
     * @Around:环绕	:是Spring中强大的通知;
     * @Around:环绕:动态代理;
     * 	try{
     * 			//前置通知
     * 			method.invoke(obj,args);
     * 			//返回通知
     * 	}catch(e){
     * 			//异常通知
     *  }finally{
     * 			//后置通知
     * 	}
     *
     * 	四合一通知就是环绕通知;
     * 	环绕通知中有一个参数:	ProceedingJoinPoint pjp
     */

    @Around("hahaMyPoint()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable{

        Object[] args = pjp.getArgs();
        String name = pjp.getSignature().getName();
        //args[0] = 100;
        Object proceed = null;
        try {
            //@Before
            System.out.println("【环绕前置通知】【"+name+"方法开始】");
            //就是利用反射调用目标方法即可,就是method.invoke(obj,args)
            proceed = pjp.proceed(args);
            //@AfterReturing
            System.out.println("【环绕返回通知】【"+name+"方法返回,返回值"+proceed+"】");
        } catch (Exception e) {
            //@AfterThrowing
            System.out.println("【环绕异常通知】【"+name+"】方法出现异常,异常信息:"+e);
            //为了让外界能知道这个异常,这个异常一定抛出去
            throw new RuntimeException(e);
        } finally{
            //@After
            System.out.println("【环绕后置通知】【"+name+"】方法结束");
        }

        //反射调用后的返回值也一定返回出去
        return proceed;
    }
    
}

没有异常的输出:  

【环绕前置通知】【div方法开始】
方法内部执行
【环绕返回通知】【div方法返回,返回值1】
【环绕后置通知】【div】方法结束

异常输出: 

【环绕前置通知】【div方法开始】
【环绕异常通知】【div】方法出现异常,异常信息:java.lang.ArithmeticException: / by zero
【环绕后置通知】【div】方法结束

java.lang.RuntimeException: java.lang.ArithmeticException: / by zero

    at com.atguigu.utils.LogUtils.myAround(LogUtils.java:62)

注:环绕通知是不存在前面的顺序问题的 


三、 单切面-环绕通知-普通通知

@Aspect
@Component
public class LogUtils {

/**
 * 告诉Spring每个方法都什么时候运行;
 * try{
 * 		@Before
 * 		method.invoke(obj,args);
 * 		@AfterReturning
 * }catch(e){
 * 		@AfterThrowing
 * }finally{
 * 		@After
 * }
 *
 * 5个通知注解
 * @Before:在目标方法之前运行;  					 前置通知
 * @After:在目标方法结束之后						后置通知
 * @AfterReturning:在目标方法正常返回之后			返回通知
 * @AfterThrowing:在目标方法抛出异常之后运行			异常通知
 * @Around:环绕								环绕通知
 *
 *
 * 抽取可重用的切入点表达式;
 * 1、随便声明一个没有实现的返回void的空方法
 * 2、给方法上标注@Pointcut注解
 */
@Pointcut("execution(public int com.atguigu.impl.MyMathCalculator.*(..))")
public void hahaMyPoint(){};


//想在执行目标方法之前运行;写切入点表达式
//execution(访问权限符  返回值类型  方法签名)
@Before("hahaMyPoint()")
public static void logStart(JoinPoint joinPoint){
    //获取到目标方法运行是使用的参数
    Object[] args = joinPoint.getArgs();
    //获取到方法签名
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-前置]【"+name+"】方法开始执行,用的参数列表【"+Arrays.asList(args)+"】");
}

//想在目标方法正常执行完成之后执行
@AfterReturning(value="hahaMyPoint()",returning="result")
public static void logReturn(JoinPoint joinPoint,Object result){
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-返回]【"+name+"】方法正常执行完成,计算结果是:"+result);
}


//想在目标方法出现异常的时候执行
@AfterThrowing(value="hahaMyPoint()",throwing="exception")
public static void logException(JoinPoint joinPoint,Exception exception) {
    System.out.println("[LogUtils-异常]【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
}

//想在目标方法结束的时候执行
@After("hahaMyPoint()")
private int logEnd(JoinPoint joinPoint) {
    System.out.println("[LogUtils-后置]【"+joinPoint.getSignature().getName()+"】方法最终结束了");
    return 0;
}

/**
 * @throws Throwable
 * @Around:环绕	:是Spring中强大的通知;
 * @Around:环绕:动态代理;
 * 	try{
 * 			//前置通知
 * 			method.invoke(obj,args);
 * 			//返回通知
 * 	}catch(e){
 * 			//异常通知
 *  }finally{
 * 			//后置通知
 * 	}
 *
 * 	四合一通知就是环绕通知;
 * 	环绕通知中有一个参数:	ProceedingJoinPoint pjp
 *
 *环绕通知:是优先于普通通知执行,执行顺序;
 *
 *[普通前置]
 *{
 *	try{
 *		环绕前置
 *		环绕执行:目标方法执行
 *		环绕返回
 *	}catch(){
 *		环绕出现异常
 *	}finally{
 *		环绕后置
 *	}
 *}
 *
 *
 *[普通后置]
 *[普通方法返回/方法异常]
 *新的顺序:
 *		(环绕前置---普通前置)----目标方法执行----环绕正常返回/出现异常-----环绕后置----普通后置---普通返回或者异常
 *注意:
 */

@Around("hahaMyPoint()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable{

    Object[] args = pjp.getArgs();
    String name = pjp.getSignature().getName();
    //args[0] = 100;
    Object proceed = null;
    try {
        //@Before
        System.out.println("【环绕前置通知】【"+name+"方法开始】");
        //就是利用反射调用目标方法即可,就是method.invoke(obj,args)
        proceed = pjp.proceed(args);
        //@AfterReturing
        System.out.println("【环绕返回通知】【"+name+"方法返回,返回值"+proceed+"】");
    } catch (Exception e) {
        //@AfterThrowing
        System.out.println("【环绕异常通知】【"+name+"】方法出现异常,异常信息:"+e);
        //为了让外界能知道这个异常,这个异常一定抛出去
        throw new RuntimeException(e);
    } finally{
        //@After
        System.out.println("【环绕后置通知】【"+name+"】方法结束");
    }

    //反射调用后的返回值也一定返回出去
    return proceed;
}
}

没有异常的输出:   

环绕前置通知】【div方法开始】
[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 1]】
方法内部执行
环绕返回通知】【div方法返回,返回值1】
环绕后置通知】【div】方法结束

[LogUtils-后置]【div】方法最终结束了
[LogUtils-返回]【div】方法正常执行完成,计算结果是:1

异常输出:  

环绕前置通知】【div方法开始】
[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 0]】
环绕异常通知】【div】方法出现异常,异常信息:java.lang.ArithmeticException: / by zero
环绕后置通知】【div】方法结束

[LogUtils-后置]【div】方法最终结束了
[LogUtils-异常]【div】方法执行出现异常了,异常信息是【java.lang.RuntimeException: java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查

java.lang.RuntimeException: java.lang.ArithmeticException: / by zero

    at com.atguigu.utils.LogUtils.myAround(LogUtils.java:143)

注:如果环绕通知显示的抛出异常,那么普通通知是感知不到异常的,这个时候普通通知还是正常执行正常返回。 


 四、多个切面-普通通知

@Aspect
@Component
@Order(1)//使用Order改变切面顺序;数值越小优先级越高
public class LogUtils {

@Pointcut("execution(public int com.atguigu.impl.MyMathCalculator.*(..))")
public void hahaMyPoint(){};

//想在执行目标方法之前运行;写切入点表达式
//execution(访问权限符  返回值类型  方法签名)
@Before("hahaMyPoint()")
public static void logStart(JoinPoint joinPoint){
    //获取到目标方法运行是使用的参数
    Object[] args = joinPoint.getArgs();
    //获取到方法签名
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-前置]【"+name+"】方法开始执行,用的参数列表【"+Arrays.asList(args)+"】");
}

//想在目标方法正常执行完成之后执行
@AfterReturning(value="hahaMyPoint()",returning="result")
public static void logReturn(JoinPoint joinPoint,Object result){
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-返回]【"+name+"】方法正常执行完成,计算结果是:"+result);
}

//想在目标方法出现异常的时候执行
@AfterThrowing(value="hahaMyPoint()",throwing="exception")
public static void logException(JoinPoint joinPoint,Exception exception) {
    System.out.println("[LogUtils-异常]【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
}

//想在目标方法结束的时候执行
@After("hahaMyPoint()")
private int logEnd(JoinPoint joinPoint) {
    System.out.println("[LogUtils-后置]【"+joinPoint.getSignature().getName()+"】方法最终结束了");
    return 0;
}

}
@Aspect
@Component
@Order(2)
public class ValidateApsect {


@Before("com.atguigu.utils.LogUtils.hahaMyPoint()")
public void logStart(JoinPoint joinPoint){
	Object[] args = joinPoint.getArgs();
	Signature signature = joinPoint.getSignature();
	String name = signature.getName();
	System.out.println("[VaApsect-前置]【"+name+"】方法开始执行,用的参数列表【"+Arrays.asList(args)+"】");
}

@AfterReturning(value="com.atguigu.utils.LogUtils.hahaMyPoint()",returning="result")
public void logReturn(JoinPoint joinPoint,Object result){
	Signature signature = joinPoint.getSignature();
	String name = signature.getName();
	System.out.println("[VaApsect-返回]【"+name+"】方法正常执行完成,计算结果是:"+result);
}

@AfterThrowing(value="com.atguigu.utils.LogUtils.hahaMyPoint()",throwing="exception")
public void logException(JoinPoint joinPoint,Exception exception) {
	System.out.println("[VaApsect-异常]【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
}

@After("com.atguigu.utils.LogUtils.hahaMyPoint()")
private int logEnd(JoinPoint joinPoint) {
	System.out.println("[VaApsect-后置]【"+joinPoint.getSignature().getName()+"】方法最终结束了");
	return 0;
}
}

 没有异常的输出:  

[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 1]】
[VaApsect-前置]【div】方法开始执行,用的参数列表【[1, 1]】
方法内部执行
[VaApsect-后置]【div】方法最终结束了
[VaApsect-返回]【div】方法正常执行完成,计算结果是:1
[LogUtils-后置]【div】方法最终结束了
[LogUtils-返回]【div】方法正常执行完成,计算结果是:1

异常输出:  

[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 0]】
[VaApsect-前置]【div】方法开始执行,用的参数列表【[1, 0]】
[VaApsect-后置]【div】方法最终结束了
[VaApsect-异常]【div】方法执行出现异常了,异常信息是【java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查
[LogUtils-后置]【div】方法最终结束了
[LogUtils-异常]【div】方法执行出现异常了,异常信息是【java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查

java.lang.ArithmeticException: / by zero

    at com.atguigu.impl.MyMathCalculator.div(MyMathCalculator.java:39)

 注:通知的执行顺序就是先进后出的执行顺序。谁先执行是按照通知类的类名字典序排序,当然可以用 @Order() 指定,值越小越靠前。

 

[LogUtils-前置]【add】方法开始执行,用的参数列表【[1, 1]】
[VaApsect-前置]【add】方法开始执行,用的参数列表【[1, 1]】
方法内部执行
[VaApsect-后置]【add】方法最终结束了
[VaApsect-返回]【add】方法正常执行完成,计算结果是:2
[LogUtils-后置]【add】方法最终结束了
[LogUtils-返回]【add】方法正常执行完成,计算结果是:2

五、多切面-普通通知-环绕通知

现在我们给 LogUtils 加上环绕通知 

@Aspect
@Component
@Order(1)//使用Order改变切面顺序;数值越小优先级越高
public class LogUtils {
    
@Pointcut("execution(public int com.atguigu.impl.MyMathCalculator.*(..))")
public void hahaMyPoint(){};




//想在执行目标方法之前运行;写切入点表达式
//execution(访问权限符  返回值类型  方法签名)
@Before("hahaMyPoint()")
public static void logStart(JoinPoint joinPoint){
    //获取到目标方法运行是使用的参数
    Object[] args = joinPoint.getArgs();
    //获取到方法签名
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-前置]【"+name+"】方法开始执行,用的参数列表【"+Arrays.asList(args)+"】");
}

//想在目标方法正常执行完成之后执行
@AfterReturning(value="hahaMyPoint()",returning="result")
public static void logReturn(JoinPoint joinPoint,Object result){
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("[LogUtils-返回]【"+name+"】方法正常执行完成,计算结果是:"+result);
}


//想在目标方法出现异常的时候执行
@AfterThrowing(value="hahaMyPoint()",throwing="exception")
public static void logException(JoinPoint joinPoint,Exception exception) {
    System.out.println("[LogUtils-异常]【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
}

//想在目标方法结束的时候执行
@After("hahaMyPoint()")
private int logEnd(JoinPoint joinPoint) {
    System.out.println("[LogUtils-后置]【"+joinPoint.getSignature().getName()+"】方法最终结束了");
    return 0;
}

@Around("hahaMyPoint()")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
    
    Object[] args = pjp.getArgs();
    String name = pjp.getSignature().getName();
    //args[0] = 100;
    Object proceed = null;
    try {
        //@Before
        System.out.println("【环绕前置通知】【"+name+"方法开始】");
        //就是利用反射调用目标方法即可,就是method.invoke(obj,args)
        proceed = pjp.proceed(args);
        //@AfterReturing
        System.out.println("【环绕返回通知】【"+name+"方法返回,返回值"+proceed+"】");
    } catch (Exception e) {
        //@AfterThrowing
        System.out.println("【环绕异常通知】【"+name+"】方法出现异常,异常信息:"+e);
        //为了让外界能知道这个异常,这个异常一定抛出去
        throw new RuntimeException(e);
    } finally{
        //@After
        System.out.println("【环绕后置通知】【"+name+"】方法结束");
    }
    
    //反射调用后的返回值也一定返回出去
    return proceed;
}
}

 没有异常的输出:   

【环绕前置通知】【div方法开始】
[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 1]】
[VaApsect-前置]【div】方法开始执行,用的参数列表【[1, 1]】
方法内部执行
[VaApsect-后置]【div】方法最终结束了
[VaApsect-返回]【div】方法正常执行完成,计算结果是:1

【环绕返回通知】【div方法返回,返回值1】
【环绕后置通知】【div】方法结束

[LogUtils-后置]【div】方法最终结束了
[LogUtils-返回]【div】方法正常执行完成,计算结果是:1

异常输出:   

【环绕前置通知】【div方法开始】
[LogUtils-前置]【div】方法开始执行,用的参数列表【[1, 0]】
[VaApsect-前置]【div】方法开始执行,用的参数列表【[1, 0]】
[VaApsect-后置]【div】方法最终结束了
[VaApsect-异常]【div】方法执行出现异常了,异常信息是【java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查
【环绕异常通知】【div】方法出现异常,异常信息:java.lang.ArithmeticException: / by zero
【环绕后置通知】【div】方法结束
[LogUtils-后置]【div】方法最终结束了
[LogUtils-异常]【div】方法执行出现异常了,异常信息是【java.lang.RuntimeException: java.lang.ArithmeticException: / by zero】:;这个异常已经通知测试小组进行排查

java.lang.RuntimeException: java.lang.ArithmeticException: / by zero

    at com.atguigu.utils.LogUtils.myAround(LogUtils.java:86)

 

LogProxy{
	环绕前置
	method.invoke(){
		VaProxy{
			va前置
	   		  target
			va后置
			va返回
		}

	}
	环绕返回
	环绕后置
}
1、Spring-IOC-AOP(动态代理);多层代理
               LogAspectpRroxy{
                         try{
                              @Before
                              method.invoke()//pjp.procced(args){
                                        BAspectProxy{
                                                       @Before
                                                       method.invoke()//---目标方法
                                                         @AfterReturning
                                                        //xxxxxxxx
                                                            //修改了返回值
                                        }
                              }
                              @AfterReturning
                         }catch(e){
                               @AfterThrowing
                         }finally{
                               @After 
                         }        
               }

 注:LogUtils 里面的环绕通知,跟ValidateApsect里面的通知没有关系,他只是影响当前切面


六、如何选择通知

由于环绕通知比较强大,他能直接控制目标方法的执行。如果我们是做日志记录等仅仅感知目标方法执行,我们使用普通通知即可。如果我需要写一一个动态代理,要影响目标方法,那么我就使用环绕通知。


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

	<context:component-scan base-package="com.atguigu"/>

	<!--  开启基于注解的AOP功能;aop名称空间-->
	<aop:aspectj-autoproxy/>
</beans>
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <!--基本切面包-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.0.0.RELEASE</version>
    </dependency>

    <!--切面plus包-->

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.12</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>


</dependencies>

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值