Spring AOP核心概念与操作示例

AOP 核心概念

还记得我们Spring有两个核心的概念嘛?一个是IOC/DI,另一个是AOP咯。

先来认识两个概念:

  • AOP(Aspect Oriented Programming)面向切面编程;作用:在不惊动原始设计的基础上为其进行功能增强,类似代理模式。
  • OOP(Object Oriented Programming)面向对象编程

在这里插入图片描述

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

知识点1:@EnableAspectJAutoProxy

名称 @EnableAspectJAutoProxy
类型 配置类注解
位置 配置类定义上方
作用 开启注解格式AOP功能

知识点2:@Aspect

名称 @Aspect
类型 类注解
位置 切面类定义上方
作用 设置当前类为AOP切面类

知识点3:@Pointcut

名称 @Pointcut
类型 方法注解
位置 切入点方法定义上方
作用 设置切入点方法
属性 value(默认):切入点表达式

知识点4:@Before

名称 @Before
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行

AOP示例

项目准备

创建一个Maven项目

  • pom.xml添加Spring依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
    </dependencies>
    
  • 添加BookDao和BookDaoImpl类

    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的配置类

    @Configuration
    @ComponentScan("com.taro")
    public class SpringConfig {
          
          
    }
    
  • 编写App运行类

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

实现功能说明:

  • 目前打印save方法的时候,因为方法中有打印系统时间,所以运行的时候是可以看到系统时间
  • 对于update方法来说,就没有该功能
  • 我们要使用SpringAOP的方式在不改变update方法的前提下让其具有打印系统时间的功能。

具体AOP操作步骤

步骤1:添加依赖

pom.xml

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>
  • 因为spring-context中已经导入了spring-aop,所以不需要再单独导入spring-aop
  • 导入AspectJ的jar包,AspectJ是AOP思想的一个具体实现,Spring有自己的AOP实现,但是相比于AspectJ来说比较麻烦,所以我们直接采用Spring整合ApsectJ的方式进行AOP开发。

步骤2:定义接口与实现类

环境准备的时候,BookDaoImpl已经准备好,不需要做任何修改

步骤3:定义通知类和通知

通知就是将共性功能抽取出来后形成的方法,共性功能指的就是当前系统时间的打印。

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

类名和方法名没有要求,可以任意。

步骤4:定义切入点

BookDaoImpl中有两个方法,分别是save和update,我们要增强的是update方法,该如何定义呢?

public class MyAdvice {
    
    
    @Pointcut("execution(void com.taro.dao.BookDao.update())")
    private void pt(){
    
    }
    public void method(){
    
    
        System.out.println(System.currentTimeMillis());
    }
}

说明:

  • 切入点定义依托一个不具有实际意义的方法进行,即无参数、无返回值、方法体无实际逻辑。

步骤5:制作切面

切面是用来描述通知和切入点之间的关系,如何进行关系的绑定?

public class MyAdvice {
    
    
    @Pointcut("execution(void com.taro.dao.BookDao.update())")
    private void pt(){
    
    }
    
    @Before("pt()")
    public void method(){
    
    
        System.out.println(System.currentTimeMillis());
    }
}

绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置

在这里插入图片描述

说明:@Before翻译过来是之前,也就是说通知会在切入点方法执行之前执行,除此之前还有其他四种类型。我们后面慢慢道来。

步骤6:将通知类配给容器并标识其为切面类

@Component
@Aspect
public class MyAdvice {
    
    
    @Pointcut("execution(void com.taro.dao.BookDao.update())")
    private void pt(){
    
    }
    
    @Before("pt()")
    public void method(){
    
    
        System.out.println(System.currentTimeMillis());
    }
}

步骤7:开启注解格式AOP功能

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

步骤8:运行类编写

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是怎么定义操作的才是我们值得学习的。

猜你喜欢

转载自blog.csdn.net/weixin_45696320/article/details/130211771