在 Spring Boot 中来实现 AOP 切面实现日志统一输出

AOP全称:Aspect Oriented Programming。是一种面向切面编程的,利用预编译方式和运行期动态代理实现程序功能统一的一种技术。它也是Spring很重要的一部分,和IOC一样重要。利用AOP可以很好的对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

本文主要利用注解解决系统日志统一输出问题

话不多说,直接上代码:

工程pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mscloudmesh.aop</groupId>
    <artifactId>springboot-aop-logs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-aop-logs</name>
    <description>springboot-aop-logs</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version> 1.18.12</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

log日志注解类:

package com.mscloudmesh.aop.springbootaoplogs.annoation;
 
import java.lang.annotation.*;

/**
 * @author kevin
 * @date 2020/6/9
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Log {
    String value() default "";
}
日志切面类实现:
 
 
package com.mscloudmesh.aop.springbootaoplogs.aspect;

import com.mscloudmesh.aop.springbootaoplogs.annoation.Log;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

@Aspect
@Component
@Slf4j
public class LogAspect {

    //设置切入点:这里直接拦截被@RestController注解的类
    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void pointcut() {

    }

    /**
     * 切面方法,记录日志
     *
     * @return
     */
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long beginTime = System.currentTimeMillis();//1、开始时间 
        //利用RequestContextHolder获取requst对象
        ServletRequestAttributes requestAttr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        String uri = requestAttr.getRequest().getRequestURI();
        log.info("方法请求开始: {}  URI: {}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), uri);
        //访问目标方法的参数 可动态改变参数值
        Object[] args = joinPoint.getArgs();
        //方法名获取
        String methodName = joinPoint.getSignature().getName();
        log.info("请求方法:{}, 请求参数: {}", methodName, Arrays.toString(args));

        Signature signature = joinPoint.getSignature();
        if (!(signature instanceof MethodSignature)) {
            throw new IllegalArgumentException("非法注解");
        }
        //调用实际方法
        Object object = joinPoint.proceed();

        //获取执行的方法
        MethodSignature methodSign = (MethodSignature) signature;
        Method method = methodSign.getMethod();


        Log log_desc = AnnotationUtils.getAnnotation(method, Log.class);

        log.info("log描述:{}", log_desc.value());


        long endTime = System.currentTimeMillis();
        log.info("方法请求结束: {},  URI: {},耗时:{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), uri, endTime - beginTime);

        return object;
    }


}Controller测试类:
  
package com.mscloudmesh.aop.springbootaoplogs.controller;

import com.mscloudmesh.aop.springbootaoplogs.annoation.Log;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

@GetMapping("/log")
@Log(value = "请求了测试方法")
public String test(@RequestParam("param") String param) {
return param+":aop日志测试";
}
}

springboot主程序类:
  

package com.mscloudmesh.aop.springbootaoplogs;

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

@SpringBootApplication
public class SpringbootAopLogsApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootAopLogsApplication.class, args);
}

}

application.yml配置文件:

 

server:
port: 8080
spring:
application:
name: aop-logs

请求http://localhost:8080/log?param=kevin

输出日志:
  2020-06-09 23:04:49.793  INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect                 : 方法请求开始: 2020-06-09 23:04:49  URI: /log
2020-06-09 23:04:49.794  INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect                 : 请求方法:test, 请求参数: [kevin]
2020-06-09 23:04:49.803  INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect                 : log描述:请求了测试方法
2020-06-09 23:04:49.803  INFO 10057 --- [nio-8080-exec-1] c.m.a.s.aspect.LogAspect                 : 方法请求结束: 2020-06-09 23:04:49,  URI: /log,耗时:10

posted @ 2020-06-10 09:09  时间都哪去了  阅读(548)  评论(0编辑  收藏  举报