目录
AOP的概念
什么是AOP?
什么是SpringAOP?
为什要⽤ AOP?
AOP的作用?
AOP的组成
通知
AOP的实现
1. 添加 Spring AOP 框架⽀持。
2. 定义切面和切点。
3. 定义通知。
切点表达式
AOP的概念
什么是AOP?
AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的 集中处理。
什么是SpringAOP?
⽽ AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。
为什要⽤ AOP?
在开发中,我们对于公共方法的处理分为三个阶段:
- 每个方法都去实现(初级)
 - 抽取公共方法(中级)
 - 采用AOP的方式,对代码进行无侵入是实现(高级)
 
因此,对于这种功能统⼀,且使⽤的地⽅较多的功能,在之前我们会抽取公共方法去实现,但是现在有更好的一个办法来处理这个问题,就是AOP。
也就是使⽤ AOP 可以扩充多个对象的某个能⼒,所以 AOP 可以说是 OOP(Object Oriented Programming,⾯向对象编程)的补充和完善。
AOP的作用?
提供声明式事务;允许用户自定义切面
AOP的组成
AOP由下边四部分组成:
|   切面(Aspect)  |   由切点(Pointcut)和通知(Advice)组成,既包含了横切逻辑的定义,也包含了连接点的定义。  | 
|   连接点(Join Point)  |   应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。  | 
|   切点(Pointcut)  |   Pointcut的作用就是提供一组规则 来匹配Join Point,给满足规则的Join Point 添加Advice.  | 
|   通知(Advice)  |   切面也有目标-他必须要完成的工作。在AOP中,切面的工作被称为通知。  | 
那么是不是感觉难以理解呢?
不着急我们简单说一下, AOP使用来对某一类事情进行集中处理的,那么处理事情,这个整体就是一个切面,处理事情的范围就是切点,范围中具体的事物就是连接点,怎么处理就是通知。
简单的体系图如下:

通知
通知又名拦截器,它定义了切面是做什么以及何时使用,即在某个特定的连接点上执行的动作,它是切面的具体实现。以目标方法为参照点,根据放置位置的地方不同,通知分为如下5种类型通知:
- 前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
 - 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
 - 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
 - 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
 - 环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。
 
AOP的实现
实现步骤如下:
1. 添加 Spring AOP 框架⽀持。
2. 定义切⾯和切点。
3. 定义通知。
具体操作如下:
1. 添加 Spring AOP 框架⽀持。
首先我们建立一个新的Springboot项目,在配置文件中添加AOP框架:
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency> 
2. 定义切面和切点。
3. 定义通知。
定义一个切面:
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect
public class LoginAspect {
//定义切点
    @Pointcut("execution(* com.example.springaopdemo.controller.UserController.*(..))")
    public void pointcut(){}
//定义通知
    @Before("pointcut()")
    public void before(){
        log.info("do before,,,,");
    }
    @After("pointcut()")
    public void after(){
        log.info("do after.....");
    }
    @AfterReturning("pointcut()")
    public void afterReturning(){
        log.info("do afterReturning....");
    }
    @AfterThrowing("pointcut()")
    public  void afterThrowing(){
        log.info("do afterThrowing....");
    }
//这里注意,环绕式通知必须自己写返回结果
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint){
        Object oj=null;
        log.info("之前");
        try{
            oj=joinPoint.proceed();//调用目标方法
        }catch(Throwable e){
            throw new RuntimeException(e);
        }
        log.info("之后");
        return oj;
    } 
@Aspect是aop框架中提供的,表示是一个切面。切面类中最先定义的是切点,用@Pointcut注解表示是一个切点,括号里边是切点表达式。后边的是五大类型的通知。分别是用五大类名称进行注解。
切点表达式:
AspectJ ⽀持三种通配符
| * | 匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数) | 
| .. | 匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。 | 
| + | 表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的 所有⼦类包括本身 | 
切点表达式由切点函数组成,execution是最常用的切点函数,语法为:
![]()
修饰符和异常可以省略。
以上AOP部分的代码就已经完成,可以实现AOP的功能了,我们简单演示一下:
定义一个类来试一下它集中处理的实现:
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public String login(){
        log.info("login..");
        return "login...";
    }
    @RequestMapping("set")
    public String setup(){
        log.info("setup...");
        return "setup....";
    }
    @RequestMapping("/logout")
    public String logout(){
        log.info("logout...");
        return "logout.....";
    }
} 
在浏览器执行过后就会发现执行结果:(任意执行一个方法,这里执行第三个方法)

可以看到五类通知的执行顺序如上,但是还有一个AfterThrowing没有看到打印,为什么呢?
这是因为AfterThrowing是在出现异常后才会进行打印的,在diamagnetic中插入一条异常代码,我们就会看到他的打印了:
以上代码能看出来了,AOP的确实一类事情的集中处理,且处理的时候不会破坏原有的代码,且允许用户自定义切面。



















