package com.atguigu.spring.aop;

public interface ArithmeticCalculator {
	//加减乘除
	int add(int i, int j);
	int sub(int i, int j);
	
	int mul(int i, int j);
	int div(int i, int j);
}

package com.atguigu.spring.aop;

import org.springframework.stereotype.Component;

@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@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;
	}

}

package com.atguigu.spring.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 可以使用 @Order 注解指定切面的优先级,值越小,优先级越高
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {
	
	/*
	 * 在 com.atguigu.spring.aop.ArithmeticCalculatorImpl 接口的每一个实现类的每一个方法开始之前执行一段代码
	 */
	@Before("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))")
	public void beforeMethod(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		Object [] args = joinPoint.getArgs();
		
		//Arrays.asList 将数组转换成 list 集合
		System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
	}
	
	/**
	 * 后置通知,在方法执行后执行的代码,无论方法是否出现异常,都会执行
	 */
	@After("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))")
	public void afterMethod(JoinPoint joinPoint){
		String methodName = joinPoint.getSignature().getName();
		
		System.out.println("The method " + methodName + " ends");
	}
	
	/**
	 * 方法正常结束受执行的代码
	 * 返回通知是可以访问到方法的返回值
	 */
	@AfterReturning(value="execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))",
			returning="result")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		String methodName = joinPoint.getSignature().getName();
		
		System.out.println("The method " + methodName + " ends with " + result);
	}
	
	/**
	 * 目标方法出现异常是会执行的代码
	 * 可以访问到异常对象, 且可以指定再出现特定异常时在执行通知代码
	 */
	@AfterThrowing(value="execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))",
			throwing="e")
	public void afterThrowing(JoinPoint joinPoint, Exception e) {
		String methodName = joinPoint.getSignature().getName();
		
		System.out.println("The method " + methodName + " occurs excetion " + e);
	}
	
	/**
	 * 环绕通知需要携带 类型的参数
	 * 环绕通知类似与动态代理的全过程: 类型的参数可以决定是否执行目标方法
	 * 且环绕参数必须有返回值,返回值即为目标方法的返回值
	 */
	@Around("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(int, int))")
	public Object aroundMethod(ProceedingJoinPoint pjd) {
		Object result = null;
		String methodName = pjd.getSignature().getName();
		try {
			//前置通知
			System.out.println("The method " + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
			//执行目标方法
			result = pjd.proceed();
			//返回通知
			System.out.println("The method " + methodName + " ends with " + result);
		} catch (Throwable e) {
			//异常通知
			System.out.println("The method " + methodName + " occurs excetion  " + e);
			throw new RuntimeException(e);
		}
		//后置通知
		System.out.println("The method " + methodName + " ends");
		
		return result;
	}
}

package com.atguigu.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		ArithmeticCalculator arithmeticCalculator = (ArithmeticCalculator) ctx.getBean("arithmeticCalculator");
		
		int result = arithmeticCalculator.add(2, 3);
		System.out.println(result);
		result = arithmeticCalculator.div(12, 3);
		System.out.println(result);
	}
}