六、集成全局AOP切面,进行访问时间与日志打印

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 集成全局AOP切面,进行访问时间与日志打印
本次开发环境为:
系统:Windows 10 10.0
JDK:JRE: 1.8.0_152-release-1136-b43 amd64 JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
开发工具:IntelliJ IDEA 2018.1.8
springboot框架:2.2.0

1、在pom.xml中增加包引用

        <!-- Springboot的AOP包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2、新建一个controller包用于本次测试使用

@RestController
public class HelloWorldAOPController {
    private Logger log = LoggerFactory.getLogger(HelloWorldAOPController.class);
    /**
     * hello请求测试 实例:http://localhost:8081/hello?name=world
     * @param name 打招呼的姓名
     * @return 返回打招呼的整体语句
     */
    @RequestMapping("/hello")
    public String hello(String name){
        StringBuffer hellos = new StringBuffer();
        hellos.append("Hello ");
        hellos.append(name);
        return hellos.toString();
    }


}

3、新建一个WebTimeAspect类,用于记录日志切面,这里需要注意截止记录是在retrun后的切入点,因其是对全局controller进行的切面,因此使用@AfterReturning更合适的一些,如果我们所有均切入则使用@After更合适一些。

@Aspect
@Component
@Order(1)
public class WebTimeAspect {

    private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
    /**
     * 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
     */
    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * @param joinPoint
     */
    @Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
    public void doBefore(JoinPoint joinPoint){
        log.info("----------- WebTimeAspect doBefore -----------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * @param rvt
     */
    @AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("-----------Start WebTimeAspect doAfterReturning ------");
        log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
        log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
    }

}

4、进行测试请求响应处理时间

访问地址:http://localhost:8081/hello?name=cnHuaShao
image.png

5、新建一个WebLogAspect类,用于请求日志与响应日志的记录

@Aspect
@Component
@Order(2)
public class WebLogAspect {

    private Logger log = LoggerFactory.getLogger(WebLogAspect.class);

    /**
     * 访问localhost时打印的IP地址
     */
    private static final String IP_LOCALHOST ="0:0:0:0:0:0:0:1";

    /**
     * com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
     */
    @Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
    public void webLog(){

    }

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * @param joinPoint
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint){
        log.info("  ---------- WebLogAspect doBefore --------------");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //在系统启动时拦截器经过该位置时会触发空指针异常,这里需要进行非空判断
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();

            log.info("  地址: {}", request.getRequestURL().toString());
            log.info("  请求方式: ", request.getMethod());
            String ip = request.getRemoteAddr();
            if (!IP_LOCALHOST.equals(ip)){
                log.info("  客户端IP: {}", ip);
            }
            log.info("  请求参数: {}" + Arrays.toString(joinPoint.getArgs()));
        }
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * @param rvt
     */
    @AfterReturning(pointcut = "webLog()",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("  ------------Start WebLogAspect doAfterReturning ------");
        log.info("  响应结果 : {}",rvt.toString());
        log.info("  ------------End WebLogAspect doAfterReturning ------");
    }

    /**
     * 异常切入
     * @param error
     */
    @AfterThrowing(pointcut = "webLog()",throwing = "error")
    public void doAfterThrowing(Throwable error){
        log.error("  ------------Start WebLogAspect doAfterThrowing ------");
        log.error("请求处理过程中发生异常:{}",error.getMessage());
        log.error("  ------------Start WebLogAspect doAfterThrowing ------");
    }
}

6、进行测试日志切面

访问地址:http://localhost:8081/hello?name=cnHuaShao
image.png

至此已经实现访问时间与日志的切面,里面有一些优化还需要更改一下

1、整合切面使用包

在上述代码中每个方法头均有一个切入扫描的包路径,这样在我们日常使用配置时无法统一化管理,为了解决该问题,特将这种统一的全局值提出来。
更改WebTimeAspect类如下

@Aspect
@Component
@Order(1)
public class WebTimeAspect {

    private Logger log = LoggerFactory.getLogger(WebTimeAspect.class);
    /**
     * 声明一个线程,用于记录请求与响应整个周期期间在服务端消耗的时间
     */
    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * com.cnhuashao.rapiddevelopment.core包及所有子包下任何类的任何方法
     */
    @Pointcut("execution(* com.cnhuashao.rapiddevelopment.core..*.*(..))")
    public void webTime(){

    }

    /**
     * 在请求响应之前,即请求到达当前服务端
     * 所有demo3下的controller均经过该切面
     * 暂存:@Before("within(com.cnhuashao.rapiddevelopment.core..*.*)")
     * @param joinPoint
     */
    @Before("webTime()")
    public void doBefore(JoinPoint joinPoint){
        log.info("----------- WebTimeAspect doBefore -----------------------------------------");
        startTime.set(System.currentTimeMillis());
    }

    /**
     * 在请求响应之后,即请求已经经过controller处理返回后
     * 暂存:@AfterReturning(value = "within(com.cnhuashao.rapiddevelopment.core..*.*)",returning = "rvt")
     * @param rvt
     */
    @AfterReturning(pointcut = "webTime()",returning = "rvt")
    public void doAfterReturning(Object rvt){
        log.info("-----------Start WebTimeAspect doAfterReturning ------");
        log.info("本次处理请求耗费时间 : {}",(System.currentTimeMillis() - startTime.get()));
        log.info("-----------End WebTimeAspect doAfterReturning -------------------------------");
    }

}

2、优先级设计

在上述代码中每个aspect类的顶部都有一个注释@Order,这个注释是标记整个切面类的运行优先级的,我们的@Before与@AfterReturning根据order值执行的顺序是不一样的。
@Before order越越优先
@AfterReturning order越越优先

3、日常使用时我们应该将全局相关的切面包与配置包放到base包中,这样有利于全局化的相关信息管理。

代码示例

本文的相关例子可以查看仓库中的RapidDevelopment-demo3目录:
Gitee 地址

如果您觉得本文不错,欢迎Star支持

本文声明:

5330898-d1c72b6c90e378f3.png

知识共享许可协议
本作品由 cn華少 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
27 8
|
1月前
|
监控 应用服务中间件 定位技术
要统计Nginx的客户端IP,可以通过分析Nginx的访问日志文件来实现
要统计Nginx的客户端IP,可以通过分析Nginx的访问日志文件来实现
109 3
|
2月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
58 1
|
3月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
155 1
|
4月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP的编程实践中,设计模式是解决常见软件设计问题的最佳实践。单例模式作为设计模式中的一种,确保一个类只有一个实例,并提供全局访问点,广泛应用于配置管理、日志记录和测试框架等场景。本文将深入探讨单例模式的原理、实现方式及其在PHP中的应用,帮助开发者更好地理解和运用这一设计模式。
在PHP开发中,单例模式通过确保类仅有一个实例并提供一个全局访问点,有效管理和访问共享资源。本文详细介绍了单例模式的概念、PHP实现方式及应用场景,并通过具体代码示例展示如何在PHP中实现单例模式以及如何在实际项目中正确使用它来优化代码结构和性能。
61 2
|
5月前
|
XML Java 数据格式
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
这篇文章是Spring5框架的AOP切面编程教程,通过XML配置方式,详细讲解了如何创建被增强类和增强类,如何在Spring配置文件中定义切入点和切面,以及如何将增强逻辑应用到具体方法上。文章通过具体的代码示例和测试结果,展示了使用XML配置实现AOP的过程,并强调了虽然注解开发更为便捷,但掌握XML配置也是非常重要的。
Spring5入门到实战------11、使用XML方式实现AOP切面编程。具体代码+讲解
|
5月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
62 0
Spring高手之路22——AOP切面类的封装与解析
|
5月前
|
API 开发者
【API管理 APIM】APIM集成内部VNet后,自我访问出现(Unable to connect to the remote server)问题,而Remote Server正是APIM它自己
【API管理 APIM】APIM集成内部VNet后,自我访问出现(Unable to connect to the remote server)问题,而Remote Server正是APIM它自己
106 5
|
5月前
|
Ubuntu Linux 测试技术
在Linux中,已知 apache 服务的访问日志按天记录在服务器本地目录/app/logs 下,由于磁盘空间紧张现在要求只能保留最近7天的访问日志,请问如何解决?
在Linux中,已知 apache 服务的访问日志按天记录在服务器本地目录/app/logs 下,由于磁盘空间紧张现在要求只能保留最近7天的访问日志,请问如何解决?
|
5月前
|
应用服务中间件 Linux nginx
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
下一篇
开通oss服务