本文源码
GitHub 地址: 知了一笑
https://github.com/cicadasmile/spring-boot-base
一, AOP 切面编程
1, 什么是 AOP 编程
在软件业, AOP 为 Aspect Oriented Programming 的缩写, 意为: 面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP 是 OOP(面向对象编程) 的延续, 是软件开发中的一个热点, 也是 Spring 框架中的一个重要内容, 是函数式编程的一种衍生范型. 利用 AOP 可以对业务逻辑的各个部分进行隔离, 从而使得业务逻辑各部分之间的耦合度降低, 提高程序的可重用性, 同时提高了开发的效率.
2,AOP 编程特点
)AOP 采取横向抽取机制, 取代了传统纵向继承体系重复性代码
) 经典应用: 事务管理, 性能监视, 安全检查, 缓存 , 日志等
)aop 底层将采用代理机制进行实现
) 接口 + 实现类 :spring 采用 jdk 的动态代理 Proxy
) 实现类: 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
码云地址: 知了一笑
https://gitee.com/cicadasmile
来源: http://www.bubuko.com/infodetail-3160055.html