Spring核心——面向切面编程(AOP)


笔记于参考黑马2022版本的SSM课程

一、概念

面向切面编程,也叫面向方法编程,与面向对象编程(OOP)一样,都是一种编程思想,SpringAOP的底层通过代理模式实现。

二、作用

AOP可用于对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合性,提高程序的可重用型和开发效率。

简单来说,就是在不改动原始设计的基础上为其功能进行增强。

三、AOP核心概念

1.连接点(JoinPoint)

连接点是程序执行过程中明确的点,比如方法调用、异常抛出、字段修改等。

SpringAOP中,可以理解为方法的执行

2.切入点(Pointcut)

匹配连接点的式子

在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法。

连接点与切入点关系:

切入点就是带有通知的连接点。
或者:切入点就是——有增强的方法。

连接点范围更大。属于切入点的方法,一定属于连接点;
属于连接点的方法不一定会被增强,因此可能不属于切入点。
(某个连接点满足执行要求时,该点将被连接增强处理,该连接点也就变成了切入点。)

3.通知(Advice)

在切入点处执行的操作,也就是共性功能

springAOP中,最终以“方法”呈现

4.通知类

定义通知的类

通知可以分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)、环绕通知(Around)五类。

例如:
在这里插入图片描述

5.切面(Aspect)

描述通知与切入点的对应关系。

切面通常是一个类,可以定义切入点和通知。

6.目标对象(Target)

原始功能去掉共性功能对应的类产生的对象。这种对象无法直接完成最终工作。它可以运行,但运行过程中,对于要增强的内容,是缺失的。

对哪个类做增强,这个类对应的对象就叫目标对象。

7.代理(Proxy)

目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现。
SpringAOP采用的是代理模式实现,所以要对原始对象进行增强,就需要对原始对象创建代理对象。

在代理对象中的方法把通知内容加进去,例如MyAdvice中的method方法,就实现了增强,即代理。

四、AOP概念(配合代码理解)

有代码如下

@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        //记录程序当前执行执行(开始时间)
        Long startTime = System.currentTimeMillis();
        //业务执行万次
        for (int i = 0;i<10000;i++) {
            System.out.println("book dao save ...");
        }
        //记录程序当前执行时间(结束时间)
        Long endTime = System.currentTimeMillis();
        //计算时间差
        Long totalTime = endTime-startTime;
        //输出信息
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
    }
    public void update(){
        System.out.println("book dao update ...");
    }

    public void delete(){
        System.out.println("book dao delete ...");
    }

    public void select(){
        System.out.println("book dao select ...");
    }
}

1.连接点

我们希望让其他的方法也能够拥有save方法中的内容,于是将这部分代码抽取出来。
在这里插入图片描述

AOP中,原先的save(),update(),delete(),select()方法就称为连接点

在这里插入图片描述

2.切入点

利用切入点表达式,设置要追加功能的方法,这里设置带有“d”的方法名进行功能追加
在这里插入图片描述

@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(* com.example.dao.BookDao.*d*(..))")
    private void pt(){}

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("------------------------------");
        Long startTime = System.currentTimeMillis();
        for (int i = 0 ; i<10000 ; i++) {
            //调用原始操作
            pjp.proceed();
        }
        Long endTime = System.currentTimeMillis();
        Long totalTime = endTime-startTime;
        System.out.println("执行万次消耗时间:" + totalTime + "ms");
        return null;
    }
}

这样一来,delete(),update()就是要追加功能的方法,这样的方法就是切入点。
而select()并没有追加功能,因此不属于切入点。

在这里插入图片描述

3.通知

之前被我们抽取出来的,用于存放共性功能的方法,便称为通知。
在这里插入图片描述

4.通知类

“通知”是一个方法,Java中,方法是不能独立存在的,因此,存放通知的类便成为通知类。
在这里插入图片描述

5.切面

未来写代码时,通知可能会有多个,切入点也会有多个,那么如何知道哪个通知对应哪个切入点?
为了将通知与切入点的关系绑定,搞清楚哪个切入点需要添加哪个通知,就需要“切面”将两者绑定。

在这里插入图片描述

五、AOP实现步骤

1.导入依赖

spring-aop以及aspectJ的包,spring-aop已经包括在了spring-context中,不需再单独导入。

	<dependencies>
        <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>

2.定义接口、实现类

实现类BookDaoImpl

@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 ...");
	}
}

接口BookDao

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

3.定义通知、通知类

根据之前的例子,通知就是将共有的功能抽取出来后形成的方法,这里沿用前面例子的方法,打印系统当前时间。类、方法名任意取。

public class MyAdvice {
	public void method(){
		System.out.println(System.currentTimeMillis());
	}
}

4.定义切入点

①在通知类中写一个私有方法,且没有参数、没有返回值、没有实际逻辑

private void pt(){}

②方法上,加上切入点表达式

//表示要增强的方法是update(),update()就是切入点
@Pointcut("execution(void com.itheima.dao.BookDao.update())")
private void pt(){}

5.定义切面

绑定切入点与通知的关系(切面)
在通知上添加注解,分为前置通知Before、后置通知AfterReturning、异常通知AfterThrowing、最终通知After、环绕通知Around

	@Before("pt()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }

6.添加注解

通知类中
①使代码受spring控制——@Component
②告诉spring当做AOP进行处理——@Aspect

@Component
@Aspect
public class MyAdvice {
	...
}

③配置类里,加上@EnableAspectJAutoProxy,告诉spring,项目中有用注解开发的AOP

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class SpringConfig {
	...
}

7.启动应用

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

可以看到update方法已增强。
在这里插入图片描述

六、AOP工作流程

1.启动spring容器

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

配置了的切入点,才会被读取
在这里插入图片描述

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

匹配失败,创建对象;
匹配成功,创建原始对象(目标对象)的代理对象

回顾

目标对象(Target)

原始功能去掉共性功能对应的类产生的对象。这种对象无法直接完成最终工作。它可以运行,但运行过程中,对于要增强的内容,是缺失的。

对哪个类做增强,这个类对应的对象就叫目标对象。例如BookServiceImpl类对应的对象

代理(Proxy)

目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现。
SpringAOP采用的是代理模式实现,所以要对原始对象进行增强,就需要对原始对象创建代理对象。

在代理对象中的方法把通知内容加进去,例如MyAdvice中的method方法,就实现了增强,即代理。

4.获取Bean执行方法

获取的bean是原始对象时,调用方法并执行,完成操作

获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

5.验证是否代理对象

如果目标对象中的方法会被增强,那么容器中将存入的是目标对象的代理对象; 如果目标对象中的方法不被增强,那么容器中将存入的是目标对象本身。

修改MyAdvice中的切入点表达式,将update()改成其他名字,即不再增强update()方法,运行:
此时update方法没有被增强,IOC容器中的对象应该是目标对象本身。
在这里插入图片描述
改回update(),即增强update()方法,运行:
此时,容器中的对象应该是目标对象的代理对象。
在这里插入图片描述
注:直接打印对象,是通过对象的toString方法,无论该对象是否代理对象,打印的结果都是一样的,原因是内部对toString方法进行了重写。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring AOP面向切面编程)是Spring框架中的一个重要模块,用于实现横向关注点的模块化开发。核心概念包括以下几个部分: 1. 切面(Aspect):切面是一个模块化的单元,它封装了与横向关注点相关的行为。在Spring AOP中,切面可以是一个类,其中包含了一组通知和切点。 2.通知(Advice):通知定义了在切面的何处以及如何插入代码。在Spring AOP中,有以下几种类型的通知: - 前置通知(Before Advice):在目标方法执行之前执行的通知。 - 后置通知(After Advice):在目标方法执行之后执行的通知,无论目标方法是否抛出异常。 - 返回通知(After Returning Advice):在目标方法成功执行并返回结果后执行的通知。 - 异常通知(After Throwing Advice):在目标方法抛出异常时执行的通知。 - 环绕通知(Around Advice):在目标方法执行前后都可以执行的通知。 3. 切点(Pointcut):切点是指那些被通知所应用的连接点的集合。通过使用表达式或者注解等方式定义切点,可以精确地指定哪些方法将被通知所拦截。 4. 连接点(Join Point):连接点是在应用执行过程中能够插入切面的点。例如,在方法调用、方法执行、异常处理等时刻都是连接点。 5. 织入(Weaving):织入是将切面应用到目标对象并创建新的代理对象的过程。Spring AOP支持编译时织入、类加载时织入和运行时织入三种方式。 Spring AOP基于动态代理机制实现,通过在运行时动态生成代理对象,在目标方法执行前后插入通知代码来实现横向关注点的功能。它使得开发者能够将横向关注点与业务逻辑解耦,提高了代码的可维护性和可重用性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值