Spring AOP快速入门详解

AOP

1. AOP简介

1.1 AOP简介和作用

  • AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构
    • OOP(Object Oriented Programming)面向对象编程
  • 作用:在不惊动原始设计的基础上为其进行功能增强。简单的说就是在不改变方法源代码的基础上对方法进行功能增强。

相当于给一个函数附加功能,例如给吕布的大招 加上技能前特效:摇摆与技能后特效:唱歌,那么吕布再摁下大招,先会摇摆一下,再跳大,跳完大技能还没结束,还得唱个歌。

  • Spring理念:无入侵式/无侵入式

1.2 AOP中的核心概念

image-20220723222134876

  • 连接点(JoinPoint):正在执行的方法,例如:update()、delete()、select()等都是连接点。
  • 切入点(Pointcut):进行功能增强了的方法,例如:update()、delete()方法,select()方法没有被增强所以不是切入点,但是是连接点。
    • 在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
      • 一个具体方法:com.yyl.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知(Advice):在切入点前后执行的操作,也就是增强的共性功能
    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:通知方法所在的类叫做通知类
  • 切面(Aspect):描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法。

3.1 AOP工作流程

  1. Spring容器启动
  2. 读取所有切面配置中的切入点
  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
    • 匹配失败,创建原始对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取bean执行方法
    • 获取的bean是原始对象时,调用方法并执行,完成操作
    • 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

2. AOP入门案例

2.1 AOP入门案例思路分析

案例需求:在接口执行前输出当前系统时间

思路分析:

  1. 导入坐标(pom.xml)
  2. 制作连接点方法(原始操作,dao接口与实现类)
  3. 制作共性功能(通知类与通知)
  4. 定义切入点
  5. 绑定切入点与通知关系(切面)

2.2 AOP入门案例实现

目录结构如下所示:

image-20220723223109812

(一) 导入aop相关坐标

<dependencies>
    <!--spring核心依赖,会将spring-aop传递进来-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.10.RELEASE</version>
    </dependency>
    <!--切入点表达式依赖,目的是找到切入点方法,也就是找到要增强的方法-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
</dependencies>

在依赖中也可以找到AOP的相关依赖包

(二) 定义dao接口与实现类

dao接口:

public interface BookDao {
    
    
    public void save();
    public void update();
}

实现类:

@Repository
public class BookDaoImpl implements BookDao {
    
    

    public void save() {
    
    
        System.out.println(System.currentTimeMillis());
        System.out.println("book dao save ...");
    }
    public void update(){
    
    
        System.out.println("book dao update ...");
    }
}

(三) 定义通知类,制作通知方法

//通知类必须配置成Spring管理的bean
@Component
public class MyAdvice {
    
    
    public void method(){
    
    
        System.out.println(System.currentTimeMillis());
    }
}

(四) 定义切入点表达式、配置切面(绑定切入点与通知关系)

//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {
    
    
    //设置切入点,要求配置在方法上方
    @Pointcut("execution(void com.yyl.dao.BookDao.update())")
    private void pt(){
    
    }

    //设置在切入点pt()的前面运行当前操作(前置通知)
     @Before("pt()")
    public void methodBefore(){
    
    
        System.out.println(System.currentTimeMillis());
    }

    @After("pt()")
    public void methodAfter(){
    
    
        System.out.println(new Date());
    }
}

image-20220723222829617

(五) 在配置类中进行Spring注解包扫描和开启AOP功能

@Configuration
@ComponentScan("com.yyl")
//开启注解开发AOP功能
@EnableAspectJAutoProxy
public class SpringConfig {
    
    
}

测试类和运行结果

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = ctx.getBean(BookDao.class);
        bookDao.update();
    }
}

运行结果如下,我们可以发现我们设置的前置与后置通知方法都运行了:

image-20220723223735103

上面我们是先讲的AOP工作流程,下面我们根据这个快速入门案例再深入理解一下

下面我们按照上面步骤我们AOP工作流程理解一下刚才的程序:

  1. Spring容器启动
    加载bean
    image-20220723224433519

  2. 读取所有切面配置中的切入点

    读取MyAdvice中的配置,找到切入点void com.yyl.dao.BookDao.update()

    image-20220723224451479

  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点

    匹配方法成功,创建原始对象(目标对象)的代理对象

    image-20220723224813691

  4. 获取bean执行方法

    执行方法:

    image-20220723224843637

3. AOP核心概念

目标对象(Target):被代理的对象,也叫原始对象,该对象中的方法没有任何功能增强。
代理对象(Proxy):代理后生成的对象,由Spring帮我们创建代理对象。

3.1 在测试类中验证代理对象

探究:AOP 代理对象的概念

首先在测试类中添加如下代码,此时因为有切片的介入,所以此时会生成代理对象

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = ctx.getBean(BookDao.class);
        bookDao.update();
		//打印对象的类名
        System.out.println(bookDao.getClass());
    }
}

结果如下所示,这和我们平时打印的getClass结果不一样
image-20220723224007346

此处可以更好的理解目标对象与代理对象:

例如:上面切入点进行修改,让他找不到切入点,AOP会判定bean对应的类中的方法是否匹配到任意切入点,此时是匹配失败的,创建原始bean对象,打印的Class是原始对象的Class

image-20220723225019537

总结

相信很多同学还懵逼,下面我们以问题+解答的形式进行总结,还有其他问题,欢迎留言

问题解答

问题1:AOP的作用是什么?

AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构,AOP在不惊动原始设计的基础上为其进行功能增强。简单的说就是在不改变方法源代码的基础上对方法进行功能增强。

问题2:连接点和切入点有什么区别,二者谁的范围大?

连接点(JoinPoint)是正在执行的方法
切入点(Pointcut)是进行功能增强了的方法

二者连接点的范围更大,因为他是所有正在执行的方法,增强的方法只是其中一部分

例如上面的案例,四个方法都是连接点,但是只有save进行了功能增强,他才是切入点:
在这里插入图片描述

问题3:请描述什么是切面?

描述通知与切入点的对应关系,也就是哪些通知方法对应哪些切入点方法

如果说按照代码的理解,那么下面的整个关系绑定的流程就是切面的代码体现

问题4:在通知方法中如何定义切入点表达式?

配置在方法 上方,使用@Pointcut注解

@Pointcut("execution(void com.yyl.dao.BookDao.update())")

问题5:如何配置切面?

首先设置切入点与通知类的绑定
在这里插入图片描述
设置在上面设置的切入点的什么时机运行当前操作(例如:前置通知)
在这里插入图片描述

问题6:在配置类上如何开启AOP注解功能?

需要构建配置类,并在配置类上开启基于注解的aop模式:@EnableAspectJAutoProxy

@Configuration
@ComponentScan("com.yyl")
//开启注解开发AOP功能
@EnableAspectJAutoProxy
public class SpringConfig {
    
    
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45525272/article/details/125955628