前言

请问今天您便秘了吗?程序员坐久了真的会便秘哦,如果偶然点进了这篇小干货,就麻烦您喝杯水然后去趟厕所一边用左手托起对准嘘嘘,一边用右手滑动手机看完本篇吧。

实现

本篇AOP统一日志管理写法来源于国外知名开源框架JHipster的AOP日志管理方式

1、引入依赖

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

2、定义logback配置

1)、dev、test环境的spring-web包定义日志级别为INFO,项目包定义日志级别为DEBUG;

2)、prod环境的spring-web包定义日志级别为ERROR,项目包定义日志级别为INFO;

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="TRACE" /> <springProfile name="dev,test">
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="INFO" />
<logger name="com.example.aoplog" level="DEBUG" />
</springProfile> <springProfile name="prod">
<logger name="org.springframework.web" level="ERROR"/>
<logger name="org.springboot.sample" level="ERROR" />
<logger name="com.example.aoplog" level="INFO" />
</springProfile> </configuration>

3、编写切面类

1)、springBeanPointcut():单独定义的spring框架切入点;

2)、applicationPackagePointcut():单独定义的项目包切入点;

3)、logAfterThrowing():1和2定义的切入点抛出异常时日志格式及显示内容;

4)、logAround():1和2定义的切入点方法进入和退出时日志格式及显示内容。

package com.example.aoplog.logging;

import com.example.aoplog.constants.GloablConstants;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.stereotype.Component; import java.util.Arrays; /**
* <p>
* AOP统一日志管理 切面类
* </p>
*
* @author 福隆苑居士,公众号:【Java分享客栈】
* @since 2022/5/5 21:57
*/
@Aspect
@Component
public class LoggingAspect { private final Logger log = LoggerFactory.getLogger(this.getClass()); private final Environment env; public LoggingAspect(Environment env) {
this.env = env;
} /**
* 匹配spring框架的repositories、service、rest端点的切面
*/
@Pointcut("within(@org.springframework.stereotype.Repository *)" +
" || within(@org.springframework.stereotype.Service *)" +
" || within(@org.springframework.web.bind.annotation.RestController *)")
public void springBeanPointcut() {
// 方法为空,因为这只是一个切入点,实现在通知中。
} /**
* 匹配我们自己项目的repositories、service、rest端点的切面
*/
@Pointcut("within(com.example.aoplog.repository..*)"+
" || within(com.example.aoplog.service..*)"+
" || within(com.example.aoplog.controller..*)")
public void applicationPackagePointcut() {
// 方法为空,因为这只是一个切入点,实现在通知中。
} /**
* 记录方法抛出异常的通知
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) { // 判断环境,dev、test or prod
if (env.acceptsProfiles(Profiles.of(GloablConstants.SPRING_PROFILE_DEVELOPMENT, GloablConstants.SPRING_PROFILE_TEST))) {
log.error("Exception in {}.{}() with cause = '{}' and exception = '{}'", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e); } else {
log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL");
} } /**
* 在方法进入和退出时记录日志的通知
*
* @param joinPoint join point for advice
* @return result
* @throws Throwable throws IllegalArgumentException
*/
@Around("applicationPackagePointcut() && springBeanPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { if (log.isDebugEnabled()) {
log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
}
try {
Object result = joinPoint.proceed();
if (log.isDebugEnabled()) {
log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), result);
}
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); throw e;
} } }

4、测试

1)、写个service

package com.example.aoplog.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; /**
* <p>
* AOP统一日志管理测试服务
* </p>
*
* @author 福隆苑居士,公众号:【Java分享客栈】
* @since 2022/5/5 21:57
*/
@Service
@Slf4j
public class AopLogService { public String test(Integer id) {
return "传入的参数是:" + id;
}
}

2)、写个controller

package com.example.aoplog.controller;

import com.example.aoplog.service.AopLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* <p>
* 测试接口
* </p>
*
* @author 福隆苑居士,公众号:【Java分享客栈】
* @since 2022/4/30 11:43
*/
@RestController
@RequestMapping("/api")
@Slf4j
public class TestController { private final AopLogService aopLogService; public TestController(AopLogService aopLogService) {
this.aopLogService = aopLogService;
} @GetMapping("/test/{id}")
public ResponseEntity<String> test(@PathVariable("id") Integer id) {
return ResponseEntity.ok().body(aopLogService.test(id));
}
}

3)、设置环境

这里我试试dev,prod自己试听见没?不服一拳打哭你哦!

server:
port: 8888 # 环境:dev-开发 test-测试 prod-生产
spring:
profiles:
active: dev

4)、效果

不解释了自己看

试试异常情况,手动加个异常。

@Service
@Slf4j
public class AopLogService { public String test(Integer id) {
int i = 1/0;
return "传入的参数是:" + id;
}
}

效果

总结

OK!打完收工!

链接:https://pan.baidu.com/doc/share/flr0QYwZYPYxmWSRPbnJRw-1028798558141759

提取码:bxaa


记住,别点赞,别推荐,别关注 ,好好上个厕所喝杯水,你们今天下班前能拉出来我就心满意足了。

【Java分享客栈】超简洁SpringBoot使用AOP统一日志管理-纯干货干到便秘的更多相关文章

  1. 【Java分享客栈】SpringBoot整合WebSocket+Stomp搭建群聊项目

    前言 前两周经常有大学生小伙伴私信给我,问我可否有偿提供毕设帮助,我说暂时没有这个打算,因为工作实在太忙,现阶段无法投入到这样的领域内,其中有两个小伙伴又问到我websocket该怎么使用,想给自己的 ...

  2. 【Java分享客栈】SpringBoot线程池参数搜一堆资料还是不会配,我花一天测试换你此生明白。

    一.前言   首先说一句,如果比较忙顺路点进来的,可以先收藏,有时间或用到了再看也行:   我相信很多人会有一个困惑,这个困惑和我之前一样,就是线程池这个玩意儿,感觉很高大上,用起来很fashion, ...

  3. SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数

    SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...

  4. 【Java分享客栈】我为什么极力推荐XXL-JOB作为中小厂的分布式任务调度平台

    前言   大家好,我是福隆苑居士,今天给大家聊聊XXL-JOB的使用.   XXL-JOB是本人呆过的三家公司都使用到的分布式任务调度平台,前两家都是服务于传统行业(某大型移动基地和某大型电网),现在 ...

  5. 【Java分享客栈】一文搞定京东零售开源的AsyncTool,彻底解决异步编排问题。

    一.前言 本章主要是承接上一篇讲CompletableFuture的文章,想了解的可以先去看看案例: https://juejin.cn/post/7091132240574283813 Comple ...

  6. 【Java分享客栈】一文搞定CompletableFuture并行处理,成倍缩短查询时间。

    前言   工作中你可能会遇到很多这样的场景,一个接口,要从其他几个service调用查询方法,分别获取到需要的值之后再封装数据返回.   还可能在微服务中遇到类似的情况,某个服务的接口,要使用好几次f ...

  7. Spring MVC 中使用AOP 进行统一日志管理--XML配置实现

    1.介绍 上一篇博客写了使用AOP进行统一日志管理的注解版实现,今天写一下使用XML配置实现版本,与上篇不同的是上次我们记录的Controller层日志,这次我们记录的是Service层的日志.使用的 ...

  8. [置顶] 使用sping AOP 操作日志管理

    记录后台操作人员的登陆.退出.进入了哪个界面.增加.删除.修改等操作 在数据库中建立一张SYSLOG表,使用Sping 的AOP实现日志管理,在Sping.xml中配置 <!-- Spring ...

  9. Spring Boot 入门(五):集成 AOP 进行日志管理

    本篇文章是接着 Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理写的,按照前面几篇博客的教程,可以搭建一个简单的项目,主要包含了 Pagehelper+MyBatis 分页 ...

随机推荐

  1. 哪一个 bash 内置命令能够进行数学运算?

    bash shell 的内置命令 let 可以进行整型数的数学运算. #! /bin/bash - - let c=a+b - -

  2. 是否可以从一个静态(static)方法内部发出对非静态 (non-static)方法的调用?

    不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在 调用静态方法时可能对象并没有被初始化.

  3. 学习RabbitMQ(四)

      I. 消息中间件特点: 1,异步处理模式 消息发送者可以发送一个消息而无需等待响应,消息发送者将消息发送到一条虚拟的通道或队列上,消息接收者则订阅或监听该通道,一条消息可能最终转发给一个或多个消息 ...

  4. Go 语言 结构体

    Go 语言 结构体 引言Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型结构体是由一系列具有相同类型或不同类型的数据构成的数据集合结构体表示一项记录,比如保存图书 ...

  5. Unsafe Rust 能做什么

    在不安全的 Rust 中唯一不同的是,你可以: 对原始指针进行解引用 调用"不安全"的函数(包括 C 函数.编译器的内建指令和原始分配器. 实现"不安全"的特性 ...

  6. 2018 百度web前端面试

    面试前 正式入职一年半左右,实习半年,勉强两年经验吧,然后很惊喜收到了百度的面试邀约,约得两点钟面试,然后本人一点钟就到了,通电话之后,面试官很热情,说正在吃饭吃完饭就去找我,让我去坐着等一会,然后一 ...

  7. 居中的css:完全指南(翻译)

    这里主要参考的是CHRIS COYIER写的一篇的文章(点击查看),主要讲了关于css水平.垂直居中的一些方法,每个方法后面都有一个demo,可以在线查看效果. 1 水平 水平居中有行内元素和块元素, ...

  8. 给新手的最简单electron使用教程

    我花了两个月闲暇翻译完了文档,大概是目前最完整最实时的中文文档了,有需要可以去看看学学:github传送门,大多数的需求阅读文档即可解决,实际上,翻译文档正是我入门一项未知事物时的最简单常用的法子. ...

  9. 嵌入式框架iframe

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. mybatis 实现分页和过滤模糊查询

    基于 mybatis 的分页和过滤查询 学习内容: 分页设计 1.分页需传递的参数 2.分页需展示的数据 3.分页需展示的数据的来源 3.1.结果总数与结果集(分页原理) 3.2.总页数.上一页和下一 ...