Bootstrap

Spring:AOP面向切面案例讲解AOP核心概念

Spring的AOP,在不惊动(改动)原有设计(代码)的前提下,想给谁添加功能就给谁添加。这个也就是Spring的理念:

无入侵式/无侵入式

AOP中核心概念分别指的是什么?

  • 连接点
  • 切入点
  • 通知
  • 通知类
  • 切面
    下面以一个例子进行讲解,直接上代码:

1,配置依赖坐标

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>6.1.14</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>
  </dependencies>

2,定义接口与实现类

//接口
public interface BookDao {
    public void save();

    public void update();

    public void delete();

    public void select();
}

//实现类
@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 ...");
    }
}

3,定义通知类和通知、定义切入点、制作切面


@Component
@Aspect
public class MyAdvice {

    @Pointcut("execution(* com.itheima.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;
    }

}

讲解:

  • Pointcut(切入点)
    @Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)
    这个注解定义了一个切入点,它匹配所有在com.itheima.dao.BookDao类中以d开头的方法的执行。
    这里的*表示返回类型可以是任何类型
    而(…)表示方法可以接受任意数量和类型的参数
    *d*中的第一个星号表示返回值类型不限,d之后的星号表示方法名中必须包含字母d,但是可以在其后有其他字符。
  • Around Advice(环绕通知)
    @Around(“pt()”)
    这个注解定义了一个环绕通知,它会在切入点匹配的方法被执行之前和之后执行。
    在这个环绕通知中,首先打印了一条分割线,然后记录了开始时间,接着在一个循环中调用了原始方法10000次(pjp.proceed()),最后计算并打印了这10000次调用所花费的时间。
  • ProceedingJoinPoint 是 AspectJ 框架中的一个接口,用于表示环绕通知(@Around)中的连接点(Join Point)。连接点是指程序执行过程中的某个特定点,例如方法的调用、异常的抛出等。在环绕通知中,ProceedingJoinPoint 对象提供了访问连接点信息和控制连接点执行的能力。
    主要功能和方法:
    获取连接点的信息:
    getSignature(): 返回连接点的签名,通常是一个方法签名。
    getArgs(): 返回连接点方法的参数数组。
    getTarget(): 返回目标对象,即被增强的对象。
    getThis(): 返回代理对象,即当前执行的代理对象。
    控制连接点的执行:
    proceed(): 执行连接点的方法。如果不调用这个方法,连接点的方法将不会被执行。
    proceed(Object[] args): 使用指定的参数数组重新执行连接点的方法。

4,核心配置类,开启注解格式AOP功能

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

5,运行程序

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

运行结果:

  • bookDao.select():并没有执行增强功能,因为@Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)中d不包含select
    在这里插入图片描述
  • bookDao.delete():执行了增强功能
    在这里插入图片描述
  • bookDao.update():执行了增强功能
    在这里插入图片描述
  • bookDao.save():同样没有执行增强功能,因为@Pointcut(“execution(* com.itheima.dao.BookDao.*d*(…))”)中d不包含save

示例讲解概念

在这里插入图片描述
(1)前面一直在强调,Spring的AOP是对一个类的方法在不进行任何修改的前提下实现增强。对于上面的案例中BookServiceImpl中有save,update,deleteselect方法,这些方法我们给起了一个名字叫连接点

(2)在BookServiceImpl的四个方法中,updatedelete只有打印没有计算万次执行消耗时间,但是在运行的时候已经有该功能,那也就是说updatedelete方法都已经被增强,所以对于需要增强的方法我们给起了一个名字叫切入点

(3)执行BookServiceImpl的update和delete方法的时候都被添加了一个计算万次执行消耗时间的功能,将这个功能抽取到一个方法中,换句话说就是存放共性功能的方法,我们给起了个名字叫通知

(4)通知是要增强的内容,会有多个,切入点是需要被增强的方法,也会有多个,那哪个切入点需要添加哪个通知,就需要提前将它们之间的关系描述清楚,那么对于通知和切入点之间的关系描述,我们给起了个名字叫切面

(5)通知是一个方法,方法不能独立存在需要被写在一个类中,这个类我们也给起了个名字叫通知类

至此AOP中的核心概念就已经介绍完了,总结下:

  • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等
    • 在SpringAOP中,理解为方法的执行
  • 切入点(Pointcut):匹配连接点的式子
    • 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
      • 一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
    • 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点
  • 通知(Advice):在切入点处执行的操作,也就是共性功能
    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:定义通知的类
  • 切面(Aspect):描述通知与切入点的对应关系。

[说明]:内容主要来源黑马程序员网上资源学习

;