一、AOP
1、简介
AOP:面向切面编程,是通过预编译方式和运行期动态代理,实现在不修改源代码的情况下给程序动态统一添加功能的一种技术,同时是对OOP(面向对象编程)的补充和完善,常被用来在spring中实现日志记录、性能监控等功能。
面向对象实现日志记录,性能监控这些功能时,需要在每个对象中都添加相同的方法,这样就产生了较大的重复工作量和大量的重复代码,不利于维护,使用AOP,可以大大减少代码数量,方便维护。
2、AOP实现原理
Spring 实现AOP思想使⽤的是动态代理技术
默认状况下, Spring会根据被代理对象是否实现接⼝来选择使⽤JDK仍是CGLIB。当被代理对象没有实现
任何接⼝时, Spring会选择CGLIB。当被代理对象实现了接⼝, Spring会选择JDK官⽅的代理技术,不过能够经过配置的⽅式,让Spring强制使⽤CGLIB,
3、实现方式
springAOP的实现方式有三种,本文主要介绍纯注解方式
纯XML方式
XML+注解
纯注解方式
4、包含对象
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 … 说白了就是你要在那些controller中加入日志管理、性能监控功能,方便获取这些controller所在的包名,将这些包名抽象成一个同一个格式,比如 com.java.spring.carController 与 com.java.spring.playController 两个包名就可以写成 com.java.spring.*。如果抽象不成统一格式,也可以抽成多个格式。抽象后的格式会在后面用到。

切面(ASPECT):切面=切点+通知,说白了切面就是一个类,它里面包含了你要干的事,即通知(日志监控),以及指定你干这个事的地点,即切点(横切关注点,即统一格式包名)

通知(Advice):你要干的事,它是切面类中的一个方法。
有五种通知方式:
前置通知(@Before):在目标方法调用之前调用通知
后置通知(@After):在目标方法完成之后调用通知
环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法
返回通知(@AfterReturning):在目标方法成功执行之后调用通知
异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

目标(Target):被通知对象。即 controller类或者serviceImpl类

切入点(PointCut):定义了通知 执行的 “地点”。说白了就是指定了你干这个事(日志监控)的地点(controller)。

连接点(JointPoint):即你在那个controller的方法中添加了日志监控,程序运行过程中,这个方法调用了那种通知。

织入(Weaving)是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。

二、Spring Boot 配置AOP实例介绍

2.1  主要是对现有的spring框架进行封装
无xml配置,一切都是java进行配置

AOP:面向切面

Aspect(切面) === Advice(通知) + PointCut(切入点)

所以仍要需要做的两件事:
指定通知(Advice)
配置切入点,组装切面
2.2 面向切面编程的步骤
1、引入aop切面的编程依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

不需要再添加aspectjweaver的依赖了,因为spring-boot-starter-aop包含了aspectjweaver
2、编写用于拦截的bean

@RestController
public class AopController {

    @RequestMapping("/hello")
    public String sayHello(){
        System.out.println("hello");
        return "hello";
    }
}

3、使用注解方式定义切面(切点+通知)
注:此处假定有中格式包名

package com.stuPayment.util;

import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class WebLogAspect {
    
    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    
    @Pointcut("execution(public * com.stuPayment.controller..*.*(..))")//切入点描述 这个是controller包的切入点
    public void controllerLog(){}//签名,可以理解成这个切入点的一个名称
    
    @Pointcut("execution(public * com.stuPayment.uiController..*.*(..))")//切入点描述,这个是uiController包的切入点
    public void uiControllerLog(){}
    
    @Before("controllerLog() || uiControllerLog()") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) {
        
        
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        
         // 记录下请求内容
        logger.info("################URL : " + request.getRequestURL().toString());
        logger.info("################HTTP_METHOD : " + request.getMethod());
        logger.info("################IP : " + request.getRemoteAddr());
        logger.info("################THE ARGS OF THE CONTROLLER : " + Arrays.toString(joinPoint.getArgs()));
        
        //下面这个getSignature().getDeclaringTypeName()是获取包+类名的   然后后面的joinPoint.getSignature.getName()获取了方法名
        logger.info("################CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        //logger.info("################TARGET: " + joinPoint.getTarget());//返回的是需要加强的目标类的对象
        //logger.info("################THIS: " + joinPoint.getThis());//返回的是经过加强后的代理类的对象

    }
   

}

具体解释参考
4、启动工程,验证结果。