@Aspect运用

列子、

public interface Calculator {
     
     // 加
     public int add(int i,int j);

     // 减
    public int sub(int i,int j);

    // 乘
    public int mul(int i,int j);

    //除
    public int div(int i,int j);
}



     
  @Service
  public class MyMathCalculator implements Calculator {
        @Override
        public int add(int i, int j) {
            int result = i + j;
            return result;
        }

        @Override
        public int sub(int i, int j) {
            int result = i - j;
            return result;
        }

        @Override
        public int mul(int i, int j) {
            int result = i * j;
            return result;
        }

        @Override
        public int div(int i, int j) {
            int result = i / j;
            return result;
        }
    }


              
      /**
       * 如何将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
       *
       *
       */
      @Aspect
      @Component
  public class LogUtils {

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

/**
 *告诉spring每个方法都什么时候运行;
 *
 *  try{
 *      @Before
 *      method.invoke(obj,args);
 *      @AfterReturning
 *  }catch(e){
 *      @AfterThrowing
 *  }finally{
 *      @After
 *  }
 *
 *
 *
 *  5个通知
 * @Before:在目标方法之前运行
 * @After:在目标方法结束之后
 * @AfterReturning:在目标方法正常返回之后
 * @AfterThrowing:在目标方法抛出异常之后运行
 * @Around:环绕
 *
 * //execution(访问权限符  返回值类型  方法签名)
 *
 */

// @Before("execution(public int com.apcstudy.aop.impl.MyMathCalculator.*(..))")
@Before(value = "MyPoint()")
public static  void logStart(JoinPoint joinPoint){
    //获取到目标方法运行是使用的参数
    Object[] args = joinPoint.getArgs();
    //获取到方法签名
    Signature signature = joinPoint.getSignature();
    String name = signature.getName();
    System.out.println("【"+name+"】方法开始执行,用的参数列表【"+ Arrays.asList(args)+"】");
}

/**
 * 告诉Spring这个result用来接收返回值:
 *          returning="result";
 * @param joinPoint
 * @param result
 */
@AfterReturning(value = "execution(public int com.apcstudy..impl.MyMathCalculator.*(..))",returning = "result")
public static void logReturn(JoinPoint joinPoint,Object result){
    System.out.println("【"+joinPoint.getSignature().getName()+"】方法正常执行完成,计算结果是:"+result);
}

/**
 * 细节四:我们可以在通知方法运行的时候,拿到目标方法的详细信息;
 * 1)只需要为通知方法的参数列表上写一个参数:
 * 		JoinPoint joinPoint:封装了当前目标方法的详细信息
 * 2)、告诉Spring哪个参数是用来接收异常
 * 		throwing="exception":告诉Spring哪个参数是用来接收异常
 * 3)、Exception exception:指定通知方法可以接收哪些异常
 *
 * ajax接受服务器数据
 * 	$.post(url,function(abc){
 * 		alert(abc)
 * 	})
 */
@AfterThrowing(value = "execution(public int com.apcstudy..MyMathCalculator.*(..))",throwing = "exception")
public static void logException(JoinPoint joinPoint,Exception exception){
    System.out.println("【"+joinPoint.getSignature().getName()+"】方法执行出现异常了,异常信息是【"+exception+"】:;这个异常已经通知测试小组进行排查");
}

/**
 * Spring对通知方法的要求不严格;
 * 唯一要求的就是方法的参数列表一定不能乱写?
 *      通知方法是Spring利用反射调用的,每次方法调用得确定这个方法的参数表的值;
 *      参数表上的每一个参数,Spring都得知道是什么?
 *      JoinPoint:认识
 *      不知道的参数一定告诉Spring这是什么?
 * @param joinPoint
 * @return
 */
@After("execution(public int com.apcstudy.aop.impl.MyMathCalculator.*(..))")
private int logEnd(JoinPoint joinPoint){
    System.out.println("【"+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;
}

}


          
          
  public class AOPTest {

      ApplicationContext ioc = new ClassPathXmlApplicationContext("conf/applicationContext.xml");


/**
 * 通知方法的执行顺序;
 *
 *   try{
 *   	@Before
 *   	method.invoke(obj,args);
 *   	@AfterReturning
 *   }catch(){
 *   	@AfterThrowing
 *   }finally{
 *   	@After
 *   }
 *
 * 正常执行:  @Before(前置通知)=====@After(后置通知)====@AfterReturning(正常返回);
 * 异常执行: @Before(前置通知)=====@After(后置通知)===@AfterThrowing(方法异常)
 *
 */


@Ignore
public void test01(){
    //	一定要从容器中拿到目标对象;注意:如果想要用类型,一定要用他的接口类型,不要用本类;
    Calculator calculator = ioc.getBean(Calculator.class);
    calculator.add(2, 12);
}

@Test
public void test02(){
    //	一定要从容器中拿到目标对象;注意:如果想要用类型,一定要用他的接口类型,不要用本类;
    Calculator calculator = ioc.getBean(Calculator.class);
    calculator.add(2, 12);
    System.out.println("=================");
    calculator.div(1, 0);
}

}

@Aspect运用

@Aspect运用

上一篇:ES6系列---【promise中ajax封装函数】


下一篇:关于kubernetes的十七个实验(二)