Java SpringAOP --- AOP的使用,AOP的源码

文章目录

SpringAOP

Spring两大核心思想:IoC和AOP(AOP是面试频率最高的)

  1. AOP就是对某一类特定问题的集中处理 (AOP是一种思想),AOP是面向切面编程,OOP是面向对象编程

引入AOP依赖

  1. 在pom.xml文件中添加配置
java 复制代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

AOP的使用

  1. 实现一个AOP的实例:打印所有接口的耗时时间,这就是对所有方法的统一处理
java 复制代码
@Slf4j
@Aspect
@Component
public class TimeAspect {
    // ProceedingJoinPoint表示的作用目标方法是什么
    // 针对所有的方法都生效使用的注解
    @Around("execution(* com.example.demo.controller.*.*(..))")
    public Object timeCost(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        // 让作用的目标方法执行
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "消耗的时间: " + (end - start) + "ms");

        return result;
    }
}


AOP的详解

AOP概念(理解)

  1. 切点:一组规则 ,通过表达式来描述,告诉程序对哪些方法来进行功能增强
    切点就是要作用的路径

    切点表达式:

  2. 连接点:切面要作用的方法,目标方法,切点要描述的方法
    连接点就是作用的具体方法

  3. 通知:具体的逻辑,要做什么处理(可以理解为代码的逻辑)

  4. 切面:切点 + 通知

举个例子:
切点 就是某个班的学生
连接点 就是某个具体的学生,张三,李四

123班学生今天要进行javaee的考试,要进行的考试就是通知

AOP是对一类事情的集中处理

通知类型
  1. 接口响应正常

    都是一圈一圈执行的,Around是先执行外圈,再执行内圈的,就和一个圆环是类似的

执行顺序:

  1. 接口响应异常

执行顺序:

java 复制代码
// 主要代码

@Slf4j
@Aspect
@Component
public class AspectDemo {
    // 第一个.*是所有的类都生效,第二个.*是所有的方法都生效
    @Before("execution(* com.example.aopdemo.demos.controller.*.*(..))")
    public void doBefore(){
        log.info("执行AspectDemo before...");
    }

    @After("execution(* com.example.aopdemo.demos.controller.*.*(..))")
    public void doAfter(){
        log.info("执行AspectDemo after...");
    }

    @AfterReturning("execution(* com.example.aopdemo.demos.controller.*.*(..))")
    public void doAfterReturning(){
        log.info("执行AspectDemo afterReturning...");
    }

    @AfterThrowing("execution(* com.example.aopdemo.demos.controller.*.*(..))")
    public void doAfterThrowing(){
        log.info("执行AspectDemo afterThrowing...");
    }

    @Around("execution(* com.example.aopdemo.demos.controller.*.*(..))")
    // Around必须返回结果
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("执行AspectDemo around 前...");
        // 调用目标方法,执行结果
        Object result = joinPoint.proceed();

        log.info("执行AspectDemo around 后...");

        return result;
    }
}

// 测试代码
@RestController
public class HelloController {
        @RequestMapping("/helloo")
        public String hello(){
            return "hello";
        }

    @RequestMapping("/t1")
    public String t1(){
            int a = 10 / 0;
        return "t1";
    }
}
切点

每个方法前都要写这个切点,是不是太麻烦了??

有没有更简单的,可以把这行提取出来呢?

  1. 定义一个切点叫做pt,这个名字是可以任意取的
  2. 定义的这个切点能否在其他切面(类)中使用呢??
    这个切点可以再其他类中使用的,如果其他类需要使用,需要把切点声明为public,使用时,类的全限定名称(包 + 类名) + 切点名称

切点名称为public修饰的

在其他类中使用

  1. 当有多个切面时,切面的执行顺序是按名称进行排序的
    优先级高:先执行before,后执行After
切面的优先级
  1. 如果开发的时候,要算切面的执行顺序是怎么样的,实在是太麻烦了??
    使用@Order来定义切面的优先级

    从图中可以看出,先执行优先级高的before方法,再执行优先级低的before方法,再执行目标方法,再执行优先级低的after方法,最后执行优先级高的after方法
切点表达式
  1. 切点表达式的类型以及其写法:
java 复制代码
execution(<访问修饰符> <返回类型> <包名.类名.⽅法(⽅法参数)> <异常>)

通配符的作用:

下面这些了解就可以了

TestController 下的 public修饰, 返回类型为String 方法名为t1, 无参方法

java 复制代码
execution(public String com.example.demo.controller.TestController.t1())

省略访问修饰符

java 复制代码
execution(String com.example.demo.controller.TestController.t1())

匹配所有返回类型

java 复制代码
execution(* com.example.demo.controller.TestController.t1())

匹配TestController 下的所有无参方法

java 复制代码
execution(* com.example.demo.controller.TestController.*())

匹配TestController 下的所有方法

java 复制代码
execution(* com.example.demo.controller.TestController.*(..))

匹配controller包下所有的类的所有方法

java 复制代码
execution(* com.example.demo.controller.*.*(..))

匹配所有包下面的TestController

java 复制代码
execution(* com..TestController.*(..))

匹配com.example.demo包下, 子孙包下的所有类的所有方法

java 复制代码
execution(* com.example.demo..*(..))
注解匹配

为了解决要包含这个类的所有方法,所有的类,这种就太宽泛了,为了指定特定的路径或者是方法使用注解匹配

  1. 编写自定义的注解
  2. 使用@annotation表达式来描述切点
  3. 在连接点的方法上添加自定义注解

annotation就是注解的意思

自定义注解作用就是指定哪些方法使用 ,内部的一些内容

自定义一个注解:

java 复制代码
// METHOD表示只能作用到方法上
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface MyAspect {

}

(1) @Tatget作用的范围

(2) 注解的生命周期

常见的面试题:

Spring 原理

  1. AOP常见的实现方式:
    aspectJ自己也有实现AOP的方式,但是我们只用学Spring实现AOP的方式,虽然是Spring用了aspectJ的名字,但是也是自己实现的

代理模式

  1. Spring AOP原理是基于代理来实现的
    代理模式:有静态代理和动态代理

什么是代理模式??

举个例子:

租户直接找房东就是没有代理模式的,

租户通过中介找房东就是有代理模式的

静态代理

  1. 静态代理:在程序运行前,代理对象就已经对目标对象进行了步骤的预执行代码

举个例子:

java 复制代码
// 接口
package com.example.aopdemo.demos.proxy;

// 要实现的出租房子的接口
public interface HouseSubject{
    // 出租房子
    void rentHouse();
    // 卖房子
    void saleHouse();
}


package com.example.aopdemo.demos.proxy;

// 目标对象
// 房东
public class RealHouseSubject implements HouseSubject{

    @Override
    public void rentHouse() {
        System.out.println("我是房东,我要出租房子!");
    }

    @Override
    public void saleHouse() {
        System.out.println("我是房东,我要卖房子!");
    }
}

// 代理对象
package com.example.aopdemo.demos.proxy;

// 中介是没有房子的,最后还是需要房东来做这个工作的
public class HouseProxy implements HouseSubject{
    // 目标对象,被代理对象
    private HouseSubject houseSubject;
    public HouseProxy(HouseSubject houseSubject) {
        this.houseSubject = houseSubject;
    }

    @Override
    public void rentHouse() {
        System.out.println("开始进行代理");
        houseSubject.rentHouse();
        System.out.println("结束代理");
    }

    @Override
    public void saleHouse() {
        System.out.println("开始进行代理");
        houseSubject.saleHouse();
        System.out.println("结束代理");
    }
}

// 测试类
package com.example.aopdemo.demos.proxy;

public class Main {
    public static void main(String[] args) {
        // 目标对象
        // 静态代理:在代理的时候,就知道了是哪个对象
        HouseSubject subject = new RealHouseSubject();
        HouseSubject proxy = new HouseProxy(subject);
        proxy.rentHouse();
    }
}
  1. 代理模式的主要角色:
    proxy就是代理的意思,以后在读源码的时候看到这个就翻译为代理

动态代理

  1. 动态代理常见的实现方式:
    (1) JDK
    (2) CGlib:这是第三方提供的

(1) JDK

动态代理和静态代理只需要理解就行,不需要自己写代码
JDK只能代理接口,不能代理类,这是规定

(2) CGLIB 动态代理实现

添加依赖:

java 复制代码
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

通过反射进行实现:

代理的目的:对目标对象进行功能的增强

CGLIB 既可以代理类,又可以代理接口

AOP的源码(了解)

容易考面试题:
SpringAOP 的实现方式:
(1) execution
(2) 自定义注解

  1. Spring AOP是怎么实现的
    是基于动态代理实现的

  2. 动态代理是怎么实现的
    Spring 动态代理是基于JDK和CGlib实现的

  3. Spring 使用的是哪个?
    两个都有

  4. 什么时候使用JDK,什么时候使用CGLIB??

    那么代理接口的时候,什么时候使用JDK,什么时候使用CGLIB??

    在SpringBoot 2.X之前,类是使用cglib代理,接口是使用jdk代理

  5. JDK 和 CGLib有什么区别??
    代理类,只能使用CGlib
    代理接口,可以使用JDK,也可以使用CGLIB



设计模式考的是思想,而不是代码

最容易问的模式:

策略模式和模版模式的区别,

代理模式和适配器模式的区别,

最有可能写代码的是单例模式

相关推荐
电子云与长程纠缠3 小时前
Blender入门学习06 - 粒子
学习·blender·1024程序员节
爱看科技3 小时前
亚马逊“Amelia”智能眼镜登场,三星/微美全息加速AI+AR技术融合引领穿戴赛道!
1024程序员节
Aevget3 小时前
界面控件Kendo UI for Angular 2025 Q3亮点 - 全新的AI编码助手
ui·界面控件·kendo ui·ui开发·1024程序员节
KevinPedri3 小时前
测试:uk8s创建监控和告警同步飞书等渠道
docker·kubernetes·云计算·1024程序员节
葱头的故事3 小时前
vant van-uploader上传file文件;回显时使用imageId拼接路径
前端·1024程序员节
-森屿安年-3 小时前
STL 容器:List
开发语言·c++·list·1024程序员节
小朩3 小时前
数据结构C语言
数据结构·c#·1024程序员节
大叔_爱编程3 小时前
基于随机森林算法的Boss直聘数据分析及可视化-hadoop+django+spider
hadoop·django·1024程序员节·spider·随机森林算法·boss直聘
GIS数据转换器3 小时前
城市基础设施安全运行监管平台
大数据·运维·人工智能·物联网·安全·无人机·1024程序员节