SpringBoot:面向切面编程AOP

💥 该系列属于【SpringBoot基础】专栏,如您需查看其他SpringBoot相关文章,请您点击左边的连接

目录

一、AOP介绍

二、AOP优点

三、AOP关键概念

1. 连接点

2. 通知

3. 切入点

4. 切面

5. 目标对象

四、用法示例

1. 项目结构

2. 导入依赖

3. 案例:计算PersonServiceImpl所有方法的执行时间

4. 案例:在PersonServiceImpl所有方法执行前打印方法的参数个数和类型

5. 案例:使用自定义注解@MyLog为PersonServiceImpl部分方法打印执行日志


一、AOP介绍

面向切面编程(Aspect-Oriented Programming,AOP)是一种编程范式,它允许程序员通过分离横切关注点来增加模块化。在传统的面向对象编程(OOP)中,横切关注点(如日志、事务、安全等)往往散布在多个模块中,这使得代码难以维护。AOP通过在运行时将横切关注点织入到程序中,来解决这个问题。

二、AOP优点

  1. 提高模块化:AOP允许开发者将横切关注点从业务逻辑中分离出来,使得每个部分更加集中和模块化。
  2. 代码复用:横切关注点可以在多个地方重用,不需要在每个业务逻辑中重复编写。
  3. 维护方便:由于横切逻辑集中管理,所以维护起来更加方便。
  4. 减少代码耦合:通过将横切逻辑与业务逻辑分离,降低了代码间的耦合。
  5. 增强功能:可以在不修改源代码的情况下,动态地添加或删除功能。

三、AOP关键概念

1. 连接点

连接点(Join Point)是程序执行过程中的一个点,例如方法调用、异常抛出等。在Spring AOP中,仅支持方法的连接点。

2. 通知

通知(Advice)是指切面在特定的连接点处执行的动作。通知定义了切面是什么和何时使用。常见通知类型有:

  • 前置通知(Before):在连接点之前执行。
  • 后置通知(After):在连接点之后执行。
  • 返回后通知(After returning):在连接点正常完成后执行。
  • 抛出异常后通知(After throwing):在连接点抛出异常后执行。
  • 环绕通知(Around):包围一个连接点的通知,可以在方法调用前后自定义一些操作。

3. 切入点

切入点(Pointcut)是一组连接点的集合,它定义了通知应该应用到哪些连接点上。通常使用正则表达式或特定的表达式语言来定义。

4. 切面

切面(Aspect)是通知和切入点的组合,它定义了横切逻辑,并且包含了何时(切入点)和如何(通知)应用这个逻辑。

5. 目标对象

目标对象(Target Object)是被一个或多个切面所通知的对象。在Spring AOP中,目标对象总是被代理的。

四、用法示例

1. 项目结构

2. 导入依赖

<!-- 引入Spring AOP依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3. 案例:计算PersonServiceImpl所有方法的执行时间

(1)定义切面类 TimeAspect

@Aspect
@Component
// TimeAspect类是一个切面,它包含了通知(环绕通知)和切入点。
// 这个切面负责记录PersonServiceImpl类中方法的执行时间。
public class TimeAspect {
    // 目标对象是PersonServiceImpl类的实例。
    @Around("execution(* com.example.service.Impl.PersonServiceImpl.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed(); // 继续执行方法,并获取执行结果
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " 执行了 " + executionTime + " 毫秒");
        return result; // 返回目标方法的执行结果
    }
}

(2)接口测试

控制台输出:

Person com.example.service.Impl.PersonServiceImpl.findPersonById(int) 执行了 257 毫秒

4. 案例:在PersonServiceImpl所有方法执行前打印方法的参数个数和类型

(1)定义切面类 PreAnalysisAspect

@Aspect
@Component
public class PreAnalysisAspect {

    // 定义一个切点,匹配PersonServiceImpl类中所有方法的执行
    @Pointcut("execution(* com.example.service.Impl.PersonServiceImpl.*(..))")
    public void serviceMethods() {
    }

    // 前置通知,在匹配的方法执行前执行
    @Before("serviceMethods()")
    public void beforeServiceMethod(JoinPoint joinPoint) {
        
        
        // 获取方法签名
        String methodName = joinPoint.getSignature().getName();
        // 打印方法名、目标对象类型、参数类型和参数值
        System.out.println("方法名: " + methodName);
        
        
        // 获取目标对象类型
        Class<?> targetClass = joinPoint.getTarget().getClass();
        System.out.println("目标对象类型: " + targetClass.getName());
        
        // 获取方法的参数类型和参数值
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
        System.out.print("参数类型: ");
        for (Class<?> parameterType : parameterTypes) {
            System.out.print(parameterType.getName() + " ");
        }
        System.out.println();
        
        
        System.out.print("参数值: ");
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.print(arg + " ");
        }
        System.out.println();
        
    }
}

(2)接口测试

控制台输出:

方法名: findPersonById
目标对象类型: com.example.service.Impl.PersonServiceImpl
参数类型: int 
参数值: 2 

5. 案例:使用自定义注解@MyLog为PersonServiceImpl部分方法打印执行日志

(1)定义注解

package com.example.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
}

(2)定义切面类 LogAspect

@Aspect
@Component
@Slf4j
public class LogAspect {
    @Pointcut("@annotation(com.example.annotation.MyLog)")
    public void myLogMethods() {
    }

    // 环绕通知,在匹配的方法执行前后执行
    @Around("myLogMethods()")
    public Object aroundMyLogMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        // 方法执行前的日志记录
        log.info("HelloMethod before execution");
        // 执行目标方法
        Object result = joinPoint.proceed();
        // 方法执行后的日志记录
        log.info("HelloMethod after execution");
        // 返回方法的执行结果
        return result;
    }
}

(3)service

    @MyLog
    public Person findPersonById(int id) {
        return personMapper.findPersonById(id);
    }

(4)接口测试

控制台输出:

2024-07-29 21:23:16.656  INFO 182276 --- [nio-8080-exec-1] com.example.aspect.LogAspect             : HelloMethod before execution
2024-07-29 21:23:16.930  INFO 182276 --- [nio-8080-exec-1] com.example.aspect.LogAspect             : HelloMethod after execution

Spring Boot实现AOP面向切面编程的具体方法如下: 1. 首先,你需要在项目的pom.xml文件中添加spring-boot-starter-aop依赖。可以参考以下代码: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ``` 2. 然后,你需要编写一个用于拦截的bean。这个bean将包含你想要在目标方法执行前后执行的逻辑。你可以使用注解或者编程方式来定义切面。例如,你可以使用@Aspect注解来定义一个切面,然后在切面的方法上使用@Before、@After等注解来定义具体的拦截行为。 3. 接下来,你需要将切面应用到目标对象上,创建代理对象。这个过程称为织入(Weaving)。在Spring Boot中,你可以使用@EnableAspectJAutoProxy注解来启用自动代理,它会根据切面定义自动创建代理对象。 总而言之,Spring Boot实现AOP面向切面编程的具体方法包括:添加依赖、编写用于拦截的bean,以及启用自动代理。这样就能实现在目标方法执行前后执行特定逻辑的效果了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot整合aop面向切面编程过程解析](https://download.csdn.net/download/weixin_38689551/12743012)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringBoot实现AOP面向切面编程](https://blog.csdn.net/weixin_52536274/article/details/130375560)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值