springboot中注解与aop结合实现简单的日志打印

Springboot集成AOP实现日志打印

1.创建一个Maven项目

1.1 在Maven项目的pom.xml导入springboot依赖
1.2 在Maven项目的pom.xml导入springboot-aop依赖
1.3 在Maven项目的pom.xml导入lombok依赖

     <!-- 将maven项目改为springboot项目-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <dependencies>
        <!-- 导入springboot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 导入springboot-aop依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.6.5</version>
        </dependency>

        <!-- 导入lombok(打印日志到控制台)依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

1.4 在项目的java目录下创建com.kai文件,并写出springboot启动类Application

package com.kai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
      SpringApplication.run(Application.class);
  }
}

1.5 在com.kai目录下创建controller文件夹与pojo文件。在controller目录中创建Login类,在pojo目录中创建User类

package com.kai.controller;

import com.kai.pojo.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Login {
    @PostMapping("/login")
    public String login(@RequestBody User user) {
        return user.toString();
    }
}
package com.kai.pojo;
import lombok.Data;

@Data
public class User {
    private String name;
    private String sex;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}

启动项目 在Postman上进行接口测试
在这里插入图片描述

2.完成注解与aop的实现

2.1 首先项目可以跑起来,完成接口测试。
2.2 在com.kai目录下创建aop文件夹,在aop文件夹中创建log文件夹。即我们在log文件夹中实现日志注解类与日志切面。
在这里插入图片描述
2.3 完成MyLogAnnotation代码的编写

package com.kai.aop.log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;
@Retention(RetentionPolicy.RUNTIME)
// 注解放到方法上
@Target(ElementType.METHOD)
public @interface MyLogAnnotation {
    // 该注解标识在方法上的作用 比如放在登录接口上 @MyLogAnnotation(name = "登录")
    // 如果name没有默认值 则在使用注解时一定要赋值
    String name();

    String index() default "";
}

2.4 完成MyLogAspect代码的编写

package com.kai.aop.log;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Component
@Aspect
@Slf4j
public class MyLogAspect {
    
    // 切入点 对标有MyLogs注解的方法进行切入
    @Pointcut("@annotation(com.kai.aop.log.MyLogAnnotation)")
    public void log() {

    }

    // 环绕通知 方法前后都可以进行加强 并返回方法结果
    @Around("log()")
    public Object printLog(ProceedingJoinPoint proceedingJoinPoint) {
        Object proceed = null;
        try {
            // 打印方法执行之前的日志信息
            handleBefore(proceedingJoinPoint);
            // 方法执行的结果
            proceed = proceedingJoinPoint.proceed();
            // 打印方法执行过后的结果
            handleAfter(proceed);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            //System.lineSeparator():系统换行符
            log.info("=========END=========" + System.lineSeparator());
        }
        return proceed;
    }
    
    private void handleBefore(ProceedingJoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //获取被增强方法上的注解对象
        MyLogAnnotation myLogs = getMyLogs(joinPoint);
        // 在控制台打印 方法接口 信息
        log.info("=========Start=========");
        // 方法接口的路径
        log.info("URL                :{}", request.getRequestURL());
        // 方法注解上的标识内容
        log.info("Name       :{}", myLogs.name());
        // 方法的名称
        log.info("HTTP Method        :{}", request.getMethod());
        // 方法的包路径
        log.info("Class Method       :{}.{}", joinPoint.getSignature().getDeclaringTypeName(), ((MethodSignature) joinPoint.getSignature()).getName());
        // IP地址
        log.info("IP                 :{}", request.getRemoteHost());
        // 方法接口中的参数
        log.info("Request Args       :{}", Arrays.toString(joinPoint.getArgs()));
    }

    // 打印方法结果
    private void handleAfter(Object proceed) {
        log.info("Response           :{}", proceed);
    }

    // 获取注解内容
    private MyLogAnnotation getMyLogs(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        MyLogAnnotation myLogs = methodSignature.getMethod().getAnnotation(MyLogAnnotation.class);
        return myLogs;
    }
    
}

2.5 在controller目录下的Login接口的login方法上加上@MyLogAnnotation

package com.kai.controller;

import com.kai.aop.log.MyLogAnnotation;
import com.kai.pojo.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Login {
    @PostMapping("/login")
    @MyLogAnnotation(name = "登录")
    public String login(@RequestBody User user) {
        return user.toString();
    }
}

2.6 重启项目 测试login接口 控制台打印

2022-05-26 17:44:52.508  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : =========Start=========
2022-05-26 17:44:52.508  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : URL                :http://localhost:8080/login
2022-05-26 17:44:52.509  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : Name       :登录
2022-05-26 17:44:52.509  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : HTTP Method        :POST
2022-05-26 17:44:52.509  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : Class Method       :com.kai.controller.Login.login
2022-05-26 17:44:52.509  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : IP                 :0:0:0:0:0:0:0:1
2022-05-26 17:44:52.509  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : Request Args       :[User{name='曹操', sex='男', age=22}]
2022-05-26 17:44:52.511  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : Response           :User{name='曹操', sex='男', age=22}
2022-05-26 17:44:52.511  INFO 17912 --- [nio-8080-exec-1] com.kai.aop.log.MyLogAspect              : =========END=========

则成功
2.7 也可以使用前置通知与后置通知

package com.kai.aop.log;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Component
@Aspect
@Slf4j
public class MyLogAspect {
    // 切入点 对标有MyLogs注解的方法进行切入
    @Pointcut("@annotation(com.kai.aop.log.MyLogAnnotation)")
    public void log() {

    }
    
    //请求method前打印内容
    @Before("log()")
    public void methodBefore(JoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //打印请求内容
        log.info("===============请求内容===============");
        log.info("请求地址:" + request.getRequestURL().toString());
        log.info("请求方式:" + request.getMethod());
        log.info("请求类方法:" + joinPoint.getSignature());
        log.info("请求类方法参数:" + Arrays.toString(joinPoint.getArgs()));
        log.info("===============请求内容===============");
    }
    //在方法执行完结后打印返回内容
    @AfterReturning(returning = "o", pointcut = "log()")
    public void methodAfterReturing(Object o) {
        log.info("--------------返回内容----------------");
        log.info("Response内容:" + o);
        log.info("--------------返回内容----------------");
    }

}

注解与aop结合实现简单日志打印已完成 喜欢的同学可以点一个赞哦 谢谢!
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: Spring Boot可以使用注解实现AOP(面向切面编程)。AOP是一种编程范式,它将横切关注点(如日志记录、事务管理等)从业务逻辑分离出来,以便更好地实现模块化和复用性。 在Spring Boot,可以使用@Aspect注解来定义切面,使用@Pointcut注解来定义切点,使用@Before、@After、@Around等注解来定义通知。通过这些注解的组合,可以实现对方法的前置、后置、环绕等操作。 例如,下面的代码演示了如何使用注解实现AOP: ```java @Aspect @Component public class LogAspect { @Pointcut("execution(* com.example.demo.service.*.*(..))") public void pointcut() {} @Before("pointcut()") public void before(JoinPoint joinPoint) { System.out.println("before " + joinPoint.getSignature().getName()); } @After("pointcut()") public void after(JoinPoint joinPoint) { System.out.println("after " + joinPoint.getSignature().getName()); } @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around before " + joinPoint.getSignature().getName()); Object result = joinPoint.proceed(); System.out.println("around after " + joinPoint.getSignature().getName()); return result; } } ``` 在上面的代码,@Aspect注解表示这是一个切面类,@Component注解表示这是一个Spring组件。@Pointcut注解定义了切点,这里表示拦截com.example.demo.service包下的所有方法。@Before、@After、@Around注解分别表示前置通知、后置通知、环绕通知,它们的参数是切点表达式。 通过这种方式,我们可以很方便地实现AOP,将横切关注点从业务逻辑分离出来,提高代码的可维护性和可重用性。 ### 回答2: Spring Boot是一种核心框架Spring的扩展,其自动化配置和默认设置能够降低Spring应用程序的开发难度和复杂性。AOP(面向切面编程)是Spring框架非常重要的一个特性,它提供了一种方法用于跨越应用程序多个部分进行交叉剖面的分离关注点。Spring Boot使用注解实现AOP,使得切面编程的应用变得更加简单和易于维护。 Spring Boot使用AspectJ注解为Aspect提供了支持。Aspect指定义切面的类,通过使用@Aspect注释标记Aspect。在Aspect,开发者可以通过使用其他注释来定义切点和通知,以及为方便切面声明添加其他接口方法。 切点是一个表达式,它指定要应用切面的位置,例如在方法前,方法后,异常抛出,或联接点(连接点)。在Spring Boot,可以使用@Pointcut注释来定义切点表达式。可以将切点表达式定义为公共的或私有的类方法,以便重复使用。 通知是切面类的方法,它定义了在切点执行时应该执行的行为。Spring Boot支持五种类型的通知注释: - @Before:在方法执行前执行切面代码。 - @AfterReturning:当方法正常返回值后执行切面代码。 - @AfterThrowing:在方法抛出异常后执行切面代码。 - @After:在方法执行后执行切面代码,无论方法执行结果如何。 - @Around:在方法执行前和执行后执行切面代码。 在编写完AOP切面以后,还需要将其纳入到Spring IoC容器使用@Component注释将切面类注册为Spring Bean组件,并在应用程序上下文启用AspectJ自动代理。 总之,使用注释实现AOPSpring Boot非常重要和受欢迎的特征之一。将重复的代码分离到切面,确保与业务逻辑分离的代码清晰,可读性和可维护性都得到了极大的提高。 ### 回答3: Spring Boot是一个快速开发的框架,使用起来非常简便,其注解AOP也是Spring Boot框架非常常用的一种方式,本文主要介绍Spring Boot如何使用注解实现AOP注解AOPSpring框架提供的一种AOP编程的方式,它可以通过添加@Aspect注解来定义切面,通过添加@Before、@After、@Around等注解来定义具体的增强逻辑。Spring Boot实现AOP时,需要借助于AspectJ框架,同时需要定义切面和切点。 首先,需要在应用程序添加“spring-boot-starter-aop”依赖,然后定义一个被增强的Bean,并在其上添加需要增强的方法(也可以在类或者方法上添加@Aspect注解)。 然后,需要定义一个切面,并在切面上添加@Before、@After、@Around等注解来定义增强逻辑,通过AspectJ的注解方式,可以实现对方法的调用进行切面操作。 最后,需要通过在启动类添加@EnableAspectJAutoProxy注解来启用AOP代理自动创建功能。 总而言之,Spring Boot使用注解实现AOP非常简单,只需要添加依赖,定义切面,定义增强逻辑,最后在启动类启用AOP代理自动创建功能即可。注解AOP可以使得编程更加简单和便捷,同时也能够提高代码的可读性和可维护性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤居自傲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值