【Java分享客栈】超简洁SpringBoot使用AOP统一日志管理-纯干货干到便秘
前言
请问今天您便秘了吗?程序员坐久了真的会便秘哦,如果偶然点进了这篇小干货,就麻烦您喝杯水然后去趟厕所一边用左手托起对准嘘嘘,一边用右手滑动手机看完本篇吧。
实现
本篇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统一日志管理-纯干货干到便秘的更多相关文章
- 【Java分享客栈】SpringBoot整合WebSocket+Stomp搭建群聊项目
前言 前两周经常有大学生小伙伴私信给我,问我可否有偿提供毕设帮助,我说暂时没有这个打算,因为工作实在太忙,现阶段无法投入到这样的领域内,其中有两个小伙伴又问到我websocket该怎么使用,想给自己的 ...
- 【Java分享客栈】SpringBoot线程池参数搜一堆资料还是不会配,我花一天测试换你此生明白。
一.前言 首先说一句,如果比较忙顺路点进来的,可以先收藏,有时间或用到了再看也行: 我相信很多人会有一个困惑,这个困惑和我之前一样,就是线程池这个玩意儿,感觉很高大上,用起来很fashion, ...
- SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数
SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...
- 【Java分享客栈】我为什么极力推荐XXL-JOB作为中小厂的分布式任务调度平台
前言 大家好,我是福隆苑居士,今天给大家聊聊XXL-JOB的使用. XXL-JOB是本人呆过的三家公司都使用到的分布式任务调度平台,前两家都是服务于传统行业(某大型移动基地和某大型电网),现在 ...
- 【Java分享客栈】一文搞定京东零售开源的AsyncTool,彻底解决异步编排问题。
一.前言 本章主要是承接上一篇讲CompletableFuture的文章,想了解的可以先去看看案例: https://juejin.cn/post/7091132240574283813 Comple ...
- 【Java分享客栈】一文搞定CompletableFuture并行处理,成倍缩短查询时间。
前言 工作中你可能会遇到很多这样的场景,一个接口,要从其他几个service调用查询方法,分别获取到需要的值之后再封装数据返回. 还可能在微服务中遇到类似的情况,某个服务的接口,要使用好几次f ...
- Spring MVC 中使用AOP 进行统一日志管理--XML配置实现
1.介绍 上一篇博客写了使用AOP进行统一日志管理的注解版实现,今天写一下使用XML配置实现版本,与上篇不同的是上次我们记录的Controller层日志,这次我们记录的是Service层的日志.使用的 ...
- [置顶] 使用sping AOP 操作日志管理
记录后台操作人员的登陆.退出.进入了哪个界面.增加.删除.修改等操作 在数据库中建立一张SYSLOG表,使用Sping 的AOP实现日志管理,在Sping.xml中配置 <!-- Spring ...
- Spring Boot 入门(五):集成 AOP 进行日志管理
本篇文章是接着 Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理写的,按照前面几篇博客的教程,可以搭建一个简单的项目,主要包含了 Pagehelper+MyBatis 分页 ...
随机推荐
- 区分 BeanFactory 和 ApplicationContext?
BeanFactory ApplicationContext 它使用懒加载 它使用即时加载 它使用语法显式提供资源对象 它自己创建和管理资源对象 不支持国际化 支持国际化 不支持基于依赖的注解 支持基 ...
- 细说【json&pickle】dumps,loads,dump,load的区别
1 json.dumps() json.dumps()是将字典类型转化成字符串类型. import json name_emb = {'a':'1111','b':'2222','c':'3333', ...
- 学习openstack(二)
OpenStack企业私有云实践 1. 实验架构 OpenStack我们把它当作是一个全新的"Linux"系统来学习,有的时候我们也把OpenStack称之为一个新的Lin ...
- List集合工具类之"将list集合按"指定长度"进行切分Lists.partition和ListUtils.partition"
将list集合按"指定长度"进行切分,返回新的List<List<类型>>集合,如下的: 方法1:List<List<Integer>& ...
- 【动态系统的建模与分析】8_频率响应_详细数学推导 G(jw)_滤波器
- video元素和audio元素相关事件
前言 在利用video元素或audio元素读取或播放媒体数据时,会触发一系列事件,如果用js脚本来捕抓这些事件,就可以对着这些事件进行处理了. 捕抓的方式有两种: 第一种是监听的方式.使用vedio或 ...
- 彻底搞懂CSS层叠上下文、层叠等级、层叠顺序、z-index
前言 最近,在项目中遇到一个关于CSS中元素z-index属性的问题,具体问题不太好描述,总结起来就是当给元素和父元素色设置position属性和z-index相关属性后,页面上渲染的元素层级结果和我 ...
- rabitmq 登录报错:User can only log in via localhost
安装教程参考:https://blog.csdn.net/qq_43672652/article/details/107349063 修改了配置文件仍然报错,无法登录.解决办法:新建一个用户登录: 查 ...
- 大数据学习之路之ambari配置(四)
试了很多遍,内存还是不够,电脑不太行的,不建议用ambari!!! 放弃了
- Mybatis 多表实现多对多查询、添加操作
Mybatis 多表实现多对多查询.添加操作 学习内容: 1. 多对多之添加操作 1.1.需求 1.2.数据库表(多对多数据库设计需要设计中间表) 1.3.类设计 1.4.Mapper 接口和 Map ...