Spring AOP基础运用

2022-10-25 19:24:52 浏览数 (1)

模拟计算器的加减乘除,在每次调用方法前后进行模拟日志输出。

  • 配置自动扫包 和 自动完成创建代理织入切面 spring.xml
代码语言:javascript复制
<context:component-scan base-package="per.tan"/>
<aop:aspectj-autoproxy/>
  • 原始业务接口 Calc
代码语言:javascript复制
public interface Calc {
    Integer add(Integer num1, Integer num2);
    Integer min(Integer num1, Integer num2);
    Integer mul(Integer num1, Integer num2);
    Integer div(Integer num1, Integer num2);
}
  • 原始业务实现类 CalcImpl
代码语言:javascript复制
@Component
public class CalcImpl implements Calc {

    @Override
    public Integer add(Integer num1, Integer num2) {
        Integer result = num1   num2;
        System.out.println("执行业务,完成了一次加法!");
        return result;
    }

    @Override
    public Integer min(Integer num1, Integer num2) {
        Integer result = num1 - num2;
        System.out.println("执行业务,完成了一次减法!");
        return result;
    }

    @Override
    public Integer mul(Integer num1, Integer num2) {
        Integer result = num1 * num2;
        System.out.println("执行业务,完成了一次乘法!");
        return result;
    }

    @Override
    public Integer div(Integer num1, Integer num2) {
        Integer result = num1 / num2;
        System.out.println("执行业务,完成了一次除法!");
        return result;
    }
}
  • 切面类 LogAspect
代码语言:javascript复制
@Component
@Aspect
public class LogAspect {
    //指定位置,方法通配符 * ,参数通配符 .. 。
    @Before(value = "execution(public Integer per.tan.aop.CalcImpl.*(..))")
    public void before(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name   "之前记录日志[Before]"   ",参数为:"   args);
    }

    @After(value = "execution(public Integer per.tan.aop.CalcImpl.*(..))")
    public void after(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        System.out.println(name   "之后记录日志[After]");
    }

    @AfterReturning(value = "execution(public Integer per.tan.aop.CalcImpl.*(..))", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String name = joinPoint.getSignature().getName();
        System.out.println(name   "之后记录日志[AfterReturning],并拿到返回值:"   result);
    }

    @AfterThrowing(value = "execution(public Integer per.tan.aop.CalcImpl.*(..))", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String name = joinPoint.getSignature().getName();
        System.out.println(name   "之后记录日志[afterThrowing],异常信息为:"   e);
    }
}
  • 测试 Test
代码语言:javascript复制
public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Calc calc = context.getBean(Calc.class);
        calc.add(10, 2);
        System.out.println();
        calc.min(10, 2);
        System.out.println();
        calc.min(10, 2);
        System.out.println();
        calc.div(10, 2);
        System.out.println();
        calc.div(10, 0);
    }
}
  • 测试结果
代码语言:javascript复制
D:Java_JDKJDK8binjava.exe ...
五月 16, 2021 4:19:15 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7daf6ecc: startup date [Sun May 16 16:19:15 CST 2021]; root of context hierarchy
五月 16, 2021 4:19:15 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
add之前记录日志[Before],参数为:[10, 2]
执行业务,完成了一次加法!
add之后记录日志[After]
add之后记录日志[AfterReturning],并拿到返回值:12

min之前记录日志[Before],参数为:[10, 2]
执行业务,完成了一次减法!
min之后记录日志[After]
min之后记录日志[AfterReturning],并拿到返回值:8

min之前记录日志[Before],参数为:[10, 2]
执行业务,完成了一次减法!
min之后记录日志[After]
min之后记录日志[AfterReturning],并拿到返回值:8

div之前记录日志[Before],参数为:[10, 2]
执行业务,完成了一次除法!
div之后记录日志[After]
div之后记录日志[AfterReturning],并拿到返回值:5

div之前记录日志[Before],参数为:[10, 0]
div之后记录日志[After]
div之后记录日志[afterThrowing],异常信息为:java.lang.ArithmeticException: / by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at per.tan.aop.CalcImpl.div(CalcImpl.java:36)
  • 相关概念
    • 切面对象:根据切面抽象出来的对象,CalcImpl中所有方法中需要加入日志的部分,抽象成一个切面类LogAspect。
    • 通知:切面对象具体执行的代码,即非业务代码,LogAspect对象打印日志的代码。
    • 目标:被横切的对象,即CalcImpl,将通知加入其中。
    • 代理:切面对象,通知,目标混合之后的结果,即使用JDK动态代理机制创建的对象。
    • 连接点:需要被横切的位置,即通知要插入业务代码的具体位置。

Q.E.D.

0 人点赞