SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码:GitHub·点这里 || GitEE·点这里
一、AOP切面编程
1、什么是AOP编程
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2、AOP编程特点
1)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
2)经典应用:事务管理、性能监视、安全检查、缓存 、日志等
3)aop底层将采用代理机制进行实现
4)接口 + 实现类 :spring采用 jdk 的动态代理Proxy
5)实现类:spring 采用 cglib字节码增强
3、AOP中术语和图解
1)target:目标类
需要被代理的类。例如:UserService
2)Joinpoint:连接点
所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3)PointCut:切入点
已经被增强的连接点。例如:addUser()
4)advice:通知/增强
增强代码。例如:after、before
5)Weaving:织入
指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6)proxy 代理类
7) Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。

二、与SpringBoot2.0整合
1、核心依赖
<!-- AOP依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、编写日志记录注解
package com.boot.aop.config;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogFilter {
String value() default "" ;
}
3、编写日志记录的切面代码
这里分为两种情况处理,一种正常的请求日志,和系统异常的错误日志。
核心注解两个。@Aspect和@Component。
package com.boot.aop.config;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.lang.reflect.Method;
@Aspect
@Component
public class LogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class) ;
@Pointcut("@annotation(com.boot.aop.config.LogFilter)")
public void logPointCut (){
}
@Around("logPointCut()")
public Object around (ProceedingJoinPoint point) throws Throwable {
Object result = null ;
try{
// 执行方法
result = point.proceed();
// 保存请求日志
saveRequestLog(point);
} catch (Exception e){
// 保存异常日志
saveExceptionLog(point,e.getMessage());
}
return result;
}
private void saveExceptionLog (ProceedingJoinPoint point,String exeMsg){
LOGGER.info("捕获异常:"+exeMsg);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
LOGGER.info("请求路径:"+request.getRequestURL());
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
LOGGER.info("请求方法:"+method.getName());
// 获取方法上LogFilter注解
LogFilter logFilter = method.getAnnotation(LogFilter.class);
String value = logFilter.value() ;
LOGGER.info("模块描述:"+value);
Object[] args = point.getArgs();
LOGGER.info("请求参数:"+ JSONObject.toJSONString(args));
}
private void saveRequestLog (ProceedingJoinPoint point){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
LOGGER.info("请求路径:"+request.getRequestURL());
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
LOGGER.info("请求方法:"+method.getName());
// 获取方法上LogFilter注解
LogFilter logFilter = method.getAnnotation(LogFilter.class);
String value = logFilter.value() ;
LOGGER.info("模块描述:"+value);
Object[] args = point.getArgs();
LOGGER.info("请求参数:"+ JSONObject.toJSONString(args));
}
}
4、请求日志测试
@LogFilter("保存请求日志")
@RequestMapping("/saveRequestLog")
public String saveRequestLog (@RequestParam("name") String name){
return "success:"+name ;
}
切面类信息打印
/**
* 请求路径:http://localhost:8011/saveRequestLog
* 请求方法:saveRequestLog
* 模块描述:保存请求日志
* 请求参数:["cicada"]
*/
5、异常日志测试
@LogFilter("保存异常日志")
@RequestMapping("/saveExceptionLog")
public String saveExceptionLog (@RequestParam("name") String name){
int error = 100 / 0 ;
System.out.println(error);
return "success:"+name ;
}
切面类信息打印
/**
* 捕获异常:/ by zero
* 请求路径:http://localhost:8011/saveExceptionLog
* 请求方法:saveExceptionLog
* 模块描述:保存异常日志
* 请求参数:["cicada"]
*/
三、源代码地址
GitHub·地址
https://github.com/cicadasmile/spring-boot-base
GitEE·地址
https://gitee.com/cicadasmile/spring-boot-base

SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务的更多相关文章
- SpringBoot2.0 基础案例(12):基于转账案例,演示事务管理操作
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.事务管理简介 1.事务基本概念 一组业务操作ABCD,要么全部 ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- SpringBoot2.0 基础案例(14):基于Yml配置方式,实现文件上传逻辑
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.文件上传 文件上传是项目开发中一个很常用的功能,常见的如头像上 ...
- SpringBoot2.0 基础案例(07):集成Druid连接池,配置监控界面
一.Druid连接池 1.druid简介 Druid连接池是阿里巴巴开源的数据库连接池项目.Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能.功能强大,能防SQL注入,内置Login ...
- SpringBoot2.0 基础案例(16):配置Actuator组件,实现系统监控
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.Actuator简介 1.监控组件作用 在生产环境中,需要实时 ...
- SpringBoot2.0 基础案例(05):多个拦截器配置和使用场景
一.拦截器简介 1.拦截器定义 拦截器,请求的接口被访问之前,进行拦截然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. 拦截器主要用来按照指定规则拒绝请求. 2.拦截器中应用 Token令牌 ...
- SpringBoot2.0 基础案例(03):配置系统全局异常映射处理
一.异常分类 这里的异常分类从系统处理异常的角度看,主要分类两类:业务异常和系统异常. 1.业务异常 业务异常主要是一些可预见性异常,处理业务异常,用来提示用户的操作,提高系统的可操作性. 常见的业务 ...
- SpringBoot2.0 基础案例(15):配置MongoDB数据库,实现增删改查逻辑
本文源码:GitHub·点这里 || GitEE·点这里 一.NoSQL简介 1.NoSQL 概念 NoSQL( Not Only SQL ),意即"不仅仅是SQL".对不同于传统 ...
- SpringBoot2.0 基础案例(10):整合Mybatis框架,集成分页助手插件
一.Mybatis框架 1.mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获 ...
随机推荐
- 跳转appStore评分
跳转到AppStore让用户能够给我们的应用进行评分,有两种方法,一种是跳出应用,跳转到AppStore,进行评分.另一种是在应用内,内置AppStore进行评分. PS:appleID在https: ...
- 在Spring中基于JDBC进行数据访问时如何控制超时
超时分类 超时根据作用域可做如下层级划分: Transaction Timeout > Statement Timeout > JDBC Driver Socket Timeout Tra ...
- 在Linux下搭建我的世界(Minecraft)服务器
最近薅了百度云双12的羊毛,1核2G一年150.突然想起以前大学整个宿舍通宵开黑挖泥土的岁月,所以刚好趁着这台服务器,打算自己搭建一个我的世界服务器,重温一下以前的感觉. 超详细Linux搭建Java ...
- Visual Studio "无法查找或打开PDB文件"解决方法
1.问题: 使用C#语言时遇到的问题(C/C++类似,方法一致),我用qt和VS2013也遇到这种问题 编译链接都没问题,调试时出现以下错误提示: 2.解决方法 第一步: 第二步:[调 ...
- Mysql转换表存储引擎的三种方式
或许会有一些场景需要改变表的存储引擎,例如存储日志的表如果几乎只有insert和少量的select操作,为了追求更好的插入性能有可能会需要把存储引擎更换为MyISAM.但是,本文不建议在同一个数据库中 ...
- Zeppelin- Linux下安装Zeppelin
前期部署: 下载,解压,配置PATH环境(编辑/etc/profile文件,记得source一下该文件) zepplin配置参考文档:https://zeppelin.apache.org/docs/ ...
- NASNet学习笔记—— 核心一:延续NAS论文的核心机制使得能够自动产生网络结构; 核心二:采用resnet和Inception重复使用block结构思想; 核心三:利用迁移学习将生成的网络迁移到大数据集上提出一个new search space。
from:https://blog.csdn.net/xjz18298268521/article/details/79079008 NASNet总结 论文:<Learning Transfer ...
- redis持久化的方式RDB 和 AOF
redis持久化的方式RDB 和 AOF 一.对Redis持久化的探讨与理解 目前Redis持久化的方式有两种: RDB 和 AOF 首先,我们应该明确持久化的数据有什么用,答案是用于重启后的数据恢复 ...
- properties文件的解析
此文章是从网上看到一篇实用小文章,感觉不过,摘录下来的!如有问题,可及时联系,可立刻做相应处理! Java读取.properties 配置文件的几种方法 在做java工程时, 经常会将一些配置信息放到 ...
- java面试题04
1.就你所熟悉的银行业务面说一下,越详细越好 银行经验:手机银行 网上银行经验 怎么支付 转账 了解基本业务 2.了解工作流的控制,审批流程以及帐务处理么? java中怎么实现工作流.审批流程 ...