本文源码: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切面编程,解决日志记录业务的更多相关文章

  1. SpringBoot2.0 基础案例(12):基于转账案例,演示事务管理操作

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.事务管理简介 1.事务基本概念 一组业务操作ABCD,要么全部 ...

  2. 十:SpringBoot-配置AOP切面编程,解决日志记录业务

    SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...

  3. SpringBoot2.0 基础案例(14):基于Yml配置方式,实现文件上传逻辑

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.文件上传 文件上传是项目开发中一个很常用的功能,常见的如头像上 ...

  4. SpringBoot2.0 基础案例(07):集成Druid连接池,配置监控界面

    一.Druid连接池 1.druid简介 Druid连接池是阿里巴巴开源的数据库连接池项目.Druid连接池为监控而生,内置强大的监控功能,监控特性不影响性能.功能强大,能防SQL注入,内置Login ...

  5. SpringBoot2.0 基础案例(16):配置Actuator组件,实现系统监控

    本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.Actuator简介 1.监控组件作用 在生产环境中,需要实时 ...

  6. SpringBoot2.0 基础案例(05):多个拦截器配置和使用场景

    一.拦截器简介 1.拦截器定义 拦截器,请求的接口被访问之前,进行拦截然后在之前或之后加入某些操作.拦截是AOP的一种实现策略. 拦截器主要用来按照指定规则拒绝请求. 2.拦截器中应用 Token令牌 ...

  7. SpringBoot2.0 基础案例(03):配置系统全局异常映射处理

    一.异常分类 这里的异常分类从系统处理异常的角度看,主要分类两类:业务异常和系统异常. 1.业务异常 业务异常主要是一些可预见性异常,处理业务异常,用来提示用户的操作,提高系统的可操作性. 常见的业务 ...

  8. SpringBoot2.0 基础案例(15):配置MongoDB数据库,实现增删改查逻辑

    本文源码:GitHub·点这里 || GitEE·点这里 一.NoSQL简介 1.NoSQL 概念 NoSQL( Not Only SQL ),意即"不仅仅是SQL".对不同于传统 ...

  9. SpringBoot2.0 基础案例(10):整合Mybatis框架,集成分页助手插件

    一.Mybatis框架 1.mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获 ...

随机推荐

  1. 【Leetcode-easy】ZigZag Conversion

    思路1:String[numRow]行字符串数组.读取原始字符串每一个字符,设置行变量 nrow和行标志位flag(向下一行为1或向上一行为-1).将该字符连接到数组中对应的行字符串,同时nrow+= ...

  2. JMS消息可靠机制

    ActiveMQ消息签收机制: 客戶端成功接收一条消息的标志是一条消息被签收,成功应答. 消息的签收情形分两种: 1.带事务的session 如果session带有事务,并且事务成功提交,则消息被自动 ...

  3. Hadoop HA- zookeeper安装配置

    安装集群 1.1 虚拟机: 3台安装好JDK的centos Linux虚拟机 1.2 安装包: 把下载好的zookeeper安装包,官网:http://mirror.bit.edu.cn/apache ...

  4. oracle中导出sql的几个常见词语的意思

    set feedback off不显示反馈信息  “1行已插入”,大量数据装入时,显示这个也是很浪费资源和时间的. set define off 如果你某个字段里面有&字符,插入数据会出错,设 ...

  5. storm源码剖析(3):topology启动过程

    storm的topology启动过程是执行strom jar topology1.jar MAINCLASS ARG1 ARG2 鉴于前面已经分析了脚本的解析过程,现在重点分析topology1.ja ...

  6. 如何在u盘上安装系统, (非安装盘)

    在u盘中永久安装Fedora. 需要两个u盘(live usb), 一个系统镜像文件. 方法是: 用一个u盘作安装盘,  然后通过这个u盘把系统安装到另一个u盘上. 两个U盘上的文件都会被覆盖. 1. ...

  7. java面试题06

    题目: 数据库 1. 表名:g_cardapply 字段(字段名/类型/长度): g_applyno varchar 8://申请单号(关键字) g_applydate bigint 8://申请日期 ...

  8. poj 2689Prime Distance(区间素数)埃氏筛法

    这道题的L和R都很大,所以如果直接开一个1~R的数组明显会超时.但是R-L并不大,所以我们考虑把这个区间(L--R)移动到(1--(R-L+1))这个区间再开数组(就是把每个数减L再加1).接下来先用 ...

  9. [转]addEventListener的第三个参数

    如果要把HTML元素的事件与某个函数绑定起来,可以有下面三种方法,以最常见的“点击”事件为例. 方法一: 直接在对应的HTML元素标签上绑定函数 ? 1 <button id='submit'  ...

  10. Tomcat加载JSP原理

    Tomcat加载JSP主要有以下几个类: JspServlet JspServletWrapper JspCompilationContext JspRuntimeContext JsperLoade ...