Spring AOP全面详讲

发布于:2025-06-22 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、Spring AOP的概念

AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),其实说白了,面向切面编程就是面向特定方法编程。

1、连接点JoinPoint

连接点的概念:可以被AOP控制的方法在SpringAOP提供的JoinPoint当中,封装了连接点方法在执行时的相关信息。

2、通知Advice

**通知:**指哪些重复的逻辑,也就是共性功能。
需要统计各个业务方法的执行耗时的,此时我们就需要在这些业务方法运行开始之前,先记录这个方法运行的开始时间,在每一个业务方法运行结束的时候,再来记录这个方法运行的结束时间。是在AOP面向切面编程当中,我们只需要将这部分重复的代码逻辑抽取出来单独定义。抽取出来的这一部分重复的逻辑,也就是共性的功能。

3、切入点PointCut

当通知和切入点结合在一起,就形成了一个切面。通过切面就能够描述当前aop程序需要针对于哪个原始方法,在什么时候执行什么样的操作。通过切入表达式找到切入点和通知进行配合。

4、切面Aspect

切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
当通知和切入点结合在一起,就形成了一个切面。通过切面就能够描述当前aop程序需要针对于哪个原始方法,在什么时候执行什么样的操作。
MAVEN项目如果需要使用AOP的情况,则需要再pom.xml文件中加入下面的依赖:

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--AOP联盟-->
    <dependency>
      <groupId>aopalliance</groupId>
      <artifactId>aopalliance</artifactId>
      <version>1.0</version>
    </dependency>
    <!--Spring Aspects-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.0.2.RELEASE</version>
    </dependency>
    <!--aspectj-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.3</version>
    </dependency>

二、xml文件实现AOP

定义Cat类如下:

package com.example.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    private String name;
    private int age;
    private void meow() {
        System.out.println("Meow!");
    }
}

定义People类如下:

package com.example.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
    private String name;
    private int age;
    public void run(){
        System.out.println("running...");
    }
}

定义切面类如下:

package com.example.AOP;

import org.aspectj.lang.annotation.Aspect;


public class TestAOP {
    public static void yanzheng(){
        System.out.println(1);
    }
}

需要在spring.xml文件中定义如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="people" class="com.example.entity.People"></bean>
    <bean id="cat" class="com.example.entity.Cat"></bean>
    <bean id="testAop" class="com.example.AOP.TestAOP"/>
    <aop:config>
        <aop:aspect ref="testAop">
            <aop:before method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>
        </aop:aspect>
    </aop:config>
</beans>

根据上面的代码可以知道,如果想使用AOP的时候需要将类和切面类都加入到IoC容器当中。即:
<bean id="people" class="com.example.entity.People"></bean> <bean id="cat" class="com.example.entity.Cat"></bean> <bean id="testAop" class="com.example.AOP.TestAOP"/>

<aop:aspect ref="testAop">

上面这个代码块配置的是配置切面类 ref指的是切面类的bean对象。

1、前置通知(before)

xml文件配置如下:

<aop:before method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>

测试类中的代码:

    @Test
    public void test1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        People people = applicationContext.getBean("people", People.class);
        people.run();
    }

运行结果如下:
在这里插入图片描述
无论是否报错都会执行。

2、后置通知

<aop:after method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>

测试类运行结果如下:
在这里插入图片描述
无论是否报错都会执行。

3、返回通知

 <aop:after-returning method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>

测试代码:
在这里插入图片描述
当切入点方法有错误时,将没有返回值。对people做一下修改,迫使方法报错,修改如下:
在这里插入图片描述
重新测试结果:
在这里插入图片描述
没有出现返回值,所以after-returning只有代码正确,才会返回。

4、异常通知

 <aop:after-throwing method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>

当people类有错误的时候,代码执行结果如下:
在这里插入图片描述
After-throwing只有代码报错的时候才能执行。

5、环绕通知

<aop:around method="yanzheng" pointcut="execution(* com.example.entity.People.run())"/>

环绕通知会在切入方法的执行前运行,也会在切入方法执行后执行。因此通知方法需要做一下修改:

package com.example.AOP;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;


public class TestAOP {
    public static void yanzheng(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println(2+"我特殊");
        proceedingJoinPoint.proceed();
        System.out.println(1+"我是AOP");
    }
}

运行结果如下:
在这里插入图片描述

三、注解形式实现AOP

需要将通知方法的类上假日
@Controller
@Aspect

使其成为切面类
通知方法定义如下:

    @Around("execution(* com.example.entity.Cat.Meow())")
    public  void yanzheng1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println(2+"我特殊");
        proceedingJoinPoint.proceed();
        System.out.println(1+"我是AOP");
    }
    @Before("execution(* com.example.entity.Cat.Meow())")
    public  void yanzheng2() {
        
        System.out.println(1+"我是AOP");
    }
    @After("execution(* com.example.entity.Cat.Meow())")
    public  void yanzheng3() {

        System.out.println(1+"我是AOP");
    }
    @AfterReturning("execution(* com.example.entity.Cat.Meow())")
    public  void yanzheng4() {

        System.out.println(1+"我是AOP");
    }
    @AfterThrowing("execution(* com.example.entity.Cat.Meow())")
    public  void yanzheng5() {

        System.out.println(1+"我是AOP");
    }

xml中的代码如下:

    <context:component-scan base-package="com.example.entity"></context:component-scan>
    <context:component-scan base-package="com.example.AOP"></context:component-scan>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

运行结果和第二节上面相同


网站公告

今日签到

点亮在社区的每一天
去签到