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