本文源码: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. Java基础教程:面向对象编程[3]

    Java基础教程:面向对象编程[3] 内容大纲 基础编程 获取用户输入 java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入.我们可以查看Ja ...

  2. HTML5/CSS3动画下拉菜单

    在线演示 本地下载

  3. SPOJ - GSS1 —— 线段树 (结点信息合并)

    题目链接:https://vjudge.net/problem/SPOJ-GSS1 GSS1 - Can you answer these queries I #tree You are given ...

  4. 分享知识-快乐自己:JAVA中的 Iterator 和 Iterable 区别

    java.lang.Iterable  java.util.Iterator  Iterator是迭代器类,而Iterable是接口. 好多类都实现了Iterable接口,这样对象就可以调用itera ...

  5. 岭回归与Lasso回归

    线性回归的一般形式 过拟合问题及其解决方法 问题:以下面一张图片展示过拟合问题 解决方法:(1):丢弃一些对我们最终预测结果影响不大的特征,具体哪些特征需要丢弃可以通过PCA算法来实现:(2):使用正 ...

  6. C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

    网址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879 引言 我一直在探寻一个高性能的Socket客户端代码.以前,我使用Socket ...

  7. Struts2与ServletAPI解耦

    什么是与Servlet API解耦? 为了避免与servlet API耦合在一起,方便Action做单元测试, Struts2对HttpServletRequest,HttpSession,和Serv ...

  8. POJ3417Network(LCA+树上查分||树剖+线段树)

    Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has jus ...

  9. Enum定义位域, 即可以通过位操作来产生未命名的值

    通过FlagsAttribute可以实现. // A bit field or flag enumeration of harvesting seasons. [Flags] public enum ...

  10. Python3解leetcode Same TreeBinary Tree Level Order Traversal II

    问题描述: Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, fro ...