什么是Spring的AOP?利用AOP实现一个自定义注解的日志功能 Starter


一、什么是Spring的AOP?

AOP(面向切面编程,Aspect-Oriented Programming) 是一种编程范式,它允许程序员将跨越多个模块的关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,以提高代码的可重用性和模块化。Spring AOP 是 Spring Framework 提供的一种实现 AOP 的方式,通过动态代理在运行时拦截方法调用,执行横切关注点的逻辑。

核心概念:

  1. 切面(Aspect): 横切关注点的模块化表示,比如日志功能、事务管理。切面可以在多个应用模块中重用。
  2. 连接点(Join Point): 程序执行中的某个特定点,比如方法调用或异常抛出。在 Spring AOP 中,连接点通常指方法的执行。
  3. 通知(Advice): 在切面的特定位置执行的代码,比如方法执行前后。Spring 提供了多种通知类型,包括前置通知、后置通知、环绕通知等。
  4. 切入点(Pointcut): 切入点定义了通知应用的具体连接点。切入点表达式用于匹配应用程序中需要增强的特定方法。
  5. 引入(Introduction): 允许我们向现有的类中添加新方法或属性。
  6. 目标对象(Target Object): 被通知的对象,即包含了横切关注点的对象。
  7. 代理(Proxy): AOP 框架为目标对象创建的动态代理,通知通过代理在目标对象上应用。

二、实现一个自定义注解的日志功能 Starter

需求描述

我们需要创建一个 Spring Boot Starter,提供一个自定义注解 @LogExecution。这个注解可以应用在方法上,自动记录方法的全限定名、方法的参数以及方法的执行时间。目标是将日志记录功能封装在 Starter 中,以便在其他 Spring 项目中轻松复用。

实现步骤

1. 创建Spring Boot Starter项目

首先,创建一个新的 Maven 项目,并配置所需的依赖。

Maven pom.xml:

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

2. 创建自定义注解

src/main/java 目录下创建一个自定义注解 @LogExecution,用于标记需要记录日志的方法。

package com.example.logstarter.annotation;

import java.lang.annotation.*;

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

3. 创建AOP切面类

创建一个 AOP 切面类,拦截标记了 @LogExecution 注解的方法,并记录方法名、参数和执行时间。使用 @Slf4j 注解来简化日志记录操作。

package com.example.logstarter.aspect;

import com.example.logstarter.annotation.LogExecution;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
@Slf4j
public class LogExecutionAspect {

    @Around("@annotation(logExecution)")
    public Object logMethodExecution(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
        long startTime = System.currentTimeMillis();

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getDeclaringTypeName() + "." + methodSignature.getName();
        Object[] methodArgs = joinPoint.getArgs();

        log.info("执行方法名: {}", methodName);
        log.info("方法的参数: {}", Arrays.toString(methodArgs));

        try {
            return joinPoint.proceed();
        } finally {
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("方法 {} 执行耗时 {} ms", methodName, executionTime);
        }
    }
}

4. 创建自动配置类

创建一个自动配置类,用于在 Spring Boot 项目中自动注册切面类。

package com.example.logstarter.config;

import com.example.logstarter.aspect.LogExecutionAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class LogStarterAutoConfiguration {

    @Bean
    public LogExecutionAspect logExecutionAspect() {
        return new LogExecutionAspect();
    }
}

5. 配置 META-INF/spring.factories

src/main/resources/META-INF/spring.factories 文件中,配置自动配置类。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.logstarter.config.LogStarterAutoConfiguration

6. 打包发布和使用

打包并发布这个 Starter,然后在其他 Spring Boot 项目中引入这个 Starter 作为依赖。

使用示例:

在其他项目中,通过 @LogExecution 注解标记方法,即可自动记录日志。

import com.example.logstarter.annotation.LogExecution;
import org.springframework.stereotype.Service;

@Service
public class ExampleService {

    @LogExecution
    public void performTask(String taskName, int taskId) {
        // 执行任务逻辑
        System.out.println("Executing task: " + taskName + " with ID: " + taskId);
    }
}

运行结果

在应用启动后,当 performTask 方法被调用时,日志将会自动记录方法的全限定名、参数信息以及方法的执行时间。

INFO  com.example.logstarter.aspect.LogExecutionAspect - 执行方法名: com.example.demo.service.ExampleService.performTask
INFO  com.example.logstarter.aspect.LogExecutionAspect - 方法的参数: [SampleTask, 42]
INFO  com.example.logstarter.aspect.LogExecutionAspect - 方法 com.example.demo.service.ExampleService.performTask 执行耗时 25 ms

总结

通过 Spring 的 AOP 功能,我们可以将日志记录功能解耦,并封装成一个独立的 Spring Boot Starter。在实际项目中,开发人员只需简单地使用 @LogExecution 注解,就能方便地获取方法执行时的重要信息。这种方式提高了代码的可维护性和复用性,并确保日志记录逻辑统一、可靠。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值