通俗易懂的案例+代码解释AOP 切面编程

spring的三大核心:IOC控制反转、DI依赖注入、AOP面向切面编程
刚开始接触springboot项目,前两个使用的多,亲自使用AOP的机会并不多,在解决埋点bug时恰好遇到,特此梳理出来

1. 理解AOP

补充一点,这里切入就是插入的意思
参考博文,点击查看

参考博文,这篇文章的解释十分到位,本文就不多赘述什么是AOP。这里原作者解释不够严谨,记录操作日志应该在最后插入。
在这里插入图片描述

2 @ Before

2.1 controller层

@RestController
@RequestMapping("/a")
public class demo {

    @Resource
    private MyService myService;

    @ResponseBody
    @RequestMapping(value = "/b", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
    public void getPolicyFile(@RequestParam("name") String name, @RequestParam("age") Integer age) {
        myService.msgShow(name,age);
    }
}

2.2 service层

Loggable是自定义的注解

@Service
public class MyService {

    @Loggable
    public void msgShow(String name,int age) {
        System.out.println("这是service的输出结果");
    }

}

2.3 自定义注解

/**
 * @Description 定义注解:Loggable
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Loggable {

}

2.4 切面 advice

@Aspect
@Component
public class LoggingAspect {

    // 定义一个切点(自定义注解的路径),表示被该注解修饰的方法都会注入advice
    @Pointcut("@annotation(com.zjh.practice.AOP.Loggable)")
    private void logPointcut() {
    }


	// joinPoint的作用就是获取msgShow()方法的参数
    @Before("logPointcut()")
    public void logadvice(JoinPoint joinPoint){

        // 这里只是一个示例,你可以写任何处理逻辑
        System.out.println("---------Before触发了----------");

        // 获取签名
        Signature signature = joinPoint.getSignature();
        // 获取切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        // 获取即将执行的方法名
        String funcName = signature.getName();
        System.out.println(String.format("即将执行方法为: %s ,属于%s包", funcName, declaringTypeName));

        Object[] args = joinPoint.getArgs();
        String itemName = (String) args[0];
        int quantity = (int) args[1];
        System.out.println(String.format("获取的参数是%s,%d",itemName,quantity));

    }
}

输出效果


---------Before触发了----------
即将执行方法为: msgShow ,属于com.zjh.practice.AOP包
获取的参数是张三,21
这是service的输出结果

3 @ After

将@Before 换成 @After 有什么变化吗

输出效果


这是service的输出结果  (注意这条输出的位置)
---------After触发了----------
即将执行方法为: msgShow ,属于com.zjh.practice.AOP包
获取的参数是张三,21

4 @ Around

@Before只能控制在方法前执行,@After只能控制在方法后执行,那若想一起控制呢,就必须使用@Around

假设你有一个服务类 MyService,其中有一个 divide 方法执行除法操作。我们将创建一个 @Around 切面,拦截这个方法的执行,执行一些自定义逻辑,处理方法之前和之后的情况,以及异常。以下是例子:

@Aspect
@Component
public class DivisionAspect {

    @Around("execution(* com.example.service.MyService.divide(..))")
    public Object aroundDivideOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        // 在方法执行前
        System.out.println("执行除法操作前");

        try {
            // 获取方法参数
            Object[] args = joinPoint.getArgs();
            if (args.length == 2 && (int) args[1] == 0) {
                // 自定义逻辑:处理除以零的情况
                System.out.println("检测到除以零。返回默认结果。");
                return 0;
            }

            // 继续执行原始方法
            Object result = joinPoint.proceed();

            // 在方法执行后
            System.out.println("执行除法操作后");

            // 如果需要,可以修改或替代原始结果
            // 为简单起见,我们将原始结果无修改地返回
            return result;
        } catch (Exception e) {
            // 异常处理:记录异常并重新抛出
            System.out.println("执行除法操作时发生异常:" + e.getMessage());
            throw e;
        } finally {
            // 清理或额外的逻辑,无论如何都会执行
            System.out.println("在执行除法操作后的finally块");
        }
    }
}

现在,假设你有一个 MyService 类如下:

package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class MyService {

    public int divide(int dividend, int divisor) {
        // 模拟除法操作
        return dividend / divisor;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值