Spring-Aop详解(环境+配置+实现+运行结果)

Spring-Aop

Aop概念

        pring AOP(面向切面编程)是Spring框架的一个重要组成部分,它提供了在应用的多个模块中复用某些行为的能力。AOP允许开发者定义“切面”,这些切面可以封装横切关注点,如事务管理、日志记录、安全检查等,这些关注点通常分散在应用程序的多个部分。通过使用AOP,开发人员可以在不修改对象本身的代码的情况下,将这些关注点添加到应用程序中。

Spring AOP的基本组成部分

1.切面(Aspect)

        切面是横切关注点的模块化。一个切面封装了许多关注点,比如日志记录、事务管理等。一个切面包含了一系列的通知(Advice),这些通知会在特定的连接点(Joinpoint)被激活。

2.通知(Advice)

        这是在特定连接点上采取的动作。Spring支持多种类型的通知,包括但不限于:

  • @Before:在方法执行前执行。
  • @After:无论方法是否成功执行都会被执行。
  • @AfterReturning:如果方法成功执行,则会被执行。
  • @AfterThrowing:如果方法抛出了异常,则会被执行。
  • @Around:环绕通知,可以控制方法的执行流程。

3.连接点(Joinpoint):

        应用程序执行过程中的某个特定点,例如方法执行、字段访问等。

4.切入点(Pointcut)

        一个或多个连接点的集合。它是通知将要被应用的地方的定义。可以通过表达式来指定切入点,比如execution(* com.example.service.*.*(..))。

5.目标对象(Target Object):

        被一个或多个切面所通知的对象。

6.代理(Proxy):

        被织入了通知的对象。客户端代码与代理交互,而不是直接与目标对象交互。

7.织入(Weaving)

        将切面连接到其他应用程序类型或对象上的过程。织入可以在编译时、加载时或运行时进行。

环境准备

新建module:

  1. 填写Name
  2. 选择语言
  3. 选择build工具Maven
  4. ,选择jdk
  5. 填写GroupdId
  6. 填写ArtifactId
  7. 点击create

:项目创建完毕后不要忘记刷新maven,否则依赖不会导入

导入依赖

        在项目的pom文件中导入以下依赖

<dependencies>
    <!--导入spring-context依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.12</version>

    </dependency>
    <!--导入测试依赖-->
    
    <!--spring对junit-->
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>6.1.12</version>
    </dependency>

    <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.11.0</version>
            <scope>test</scope>
    </dependency>
    <!--aop相关的jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>6.1.12</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>6.1.12</version>
    </dependency>
</dependencies>

新建springConfig.xml文件

        下面是springConfig.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:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd

      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <!--配置包扫描-->
    <context:component-scan base-package="org.xiji"/>


</beans>

实体准备

package org.xiji;

import org.springframework.stereotype.Component;

/**
 * 计算类
 */
@Component
public class Calculation {

    /**
     * 相加
     */
    public int add(int a, int b)
    {
        return a + b;
    }


    /**
     * 相减
     */
    public int sub(int a, int b)
    {
        return a - b;
    }

    /**
     * 相乘
     */
    public int mul(int a, int b)
    {
        return a * b;
    }

    /**
     * 相除
     */
    public int div(int a, int b)
    {
        return a / b;
    }
}
 

编写springConfig.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:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd

      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <!--配置包扫描-->
    <context:component-scan base-package="org.xiji"/>

    <aop:aspectj-autoproxy />

</beans>

注:需要开启包扫描和aop自动代理

Spring测试类配置

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.xiji.Calculation;

/**
 *
 * JUNIT5第一种
 * @ExtendWith(SpringExtension.class)
 * @ContextConfiguration(locations = {"classpath:/SpringConfig.xml"})
 *
 *
 * JUNIT5第二种
 * @SpringJUnitConfig(locations = {"classpath:/SpringConfig.xml"})
 */
//@ExtendWith(SpringExtension.class)
//@ContextConfiguration(locations = {"classpath:/SpringConfig.xml"})

@SpringJUnitConfig(locations = {"classpath:/springConfig.xml"})
public class SpringTestJunit5 {

    @Autowired
    private Calculation calculation;

    @Test
    public void test()
    {
        System.out.println(calculation.add(1, 2));


    }
}

切点配置类

切点表达式

        "execution(权限修饰符 包名.类名.方法名(参数)) "

                * 代表任意一个

                .. 代表任意参数

前置通知

/**
 * 方法执行前执行的代码
 */
@Before("execution(* org.xiji.Calculation.*(..))")
public void before(JoinPoint joinPoint)
{
    /**
     * 遍历输出参数
     */
    System.out.println("==========================");
    Object[] args = joinPoint.getArgs();
    for (Object arg : args) {
        System.out.println(arg);
    }
    System.out.println(joinPoint.getSignature().getName());
    System.out.println(joinPoint.getTarget());
    System.out.println("Aop前置处理器");
    System.out.println("before");
    System.out.println("==========================");
}

后置通知

/**
 * 后置方法,无论方法执行是否成功都会返回
 */
@After("execution(* org.xiji.Calculation.*(..))")
public void after(JoinPoint joinPoint)
{
    System.out.println("==========================");
    System.out.println(joinPoint.getTarget());
    System.out.println("Aop后置处理器");
    System.out.println("after");
    System.out.println("==========================");
}

返回通知

注:returning 的名字,与参数中接受返回结果的值是一致的

/**
 *
 * 返回处理器
 */
@AfterReturning(pointcut = "execution(* org.xiji.Calculation.*(..))",returning = "returning")
public void afterReturning(JoinPoint joinPoint,Object returning)
{
    System.out.println("==========================");
    System.out.println(returning.toString());
    System.out.println(joinPoint.getTarget());
    System.out.println("Aop返回处理器");
    System.out.println("afterReturning");
    System.out.println("==========================");
}

异常通知

注:throwing 定义的参数是throwable 那么在接受参数时的名字也是 throwable

/**
 * 异常处理器
 */
@AfterThrowing(pointcut = "execution(* org.xiji.Calculation.*(..))",throwing = "throwable")
public void afterThrowing(JoinPoint joinPoint,Throwable throwable)
{
    System.out.println("==========================");
    System.out.println(throwable.getMessage());
    System.out.println(joinPoint.getTarget());
    System.out.println("Aop异常处理器");
    System.out.println("afterThrowing");
    System.out.println("==========================");
}

定义切点

/**
 * 定义切点
 */
@Pointcut("execution(* org.xiji.Calculation.*(..))")
public void pointCut()
{

}

注:使用切点时直接 输入pointCut() 即可

环绕通知

/**
 * 环绕通知
 */
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint)
{
    Object result = null;
    try {
        System.out.println("环绕通知前");
        result = joinPoint.proceed();
        System.out.println("result = " + result);
        System.out.println("环绕通知后");
    } catch (Throwable throwable) {
        System.out.println("环绕通知异常");
        throwable.printStackTrace();
    }finally {
            System.out.println("无论结果好坏必然运行");
    }
    return result;
}

完整的Point类

package org.xiji;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


@Component
@Aspect
public class PointCutAop {

    /**
     * 方法执行前执行的代码
     */
    @Before("execution(* org.xiji.Calculation.*(..))")
    public void before(JoinPoint joinPoint)
    {
        /**
         * 遍历输出参数
         */
        System.out.println("==========================");
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println(arg);
        }
        System.out.println(joinPoint.getSignature().getName());
        System.out.println(joinPoint.getTarget());
        System.out.println("Aop前置处理器");
        System.out.println("before");
        System.out.println("==========================");
    }

    /**
     * 后置方法,无论方法执行是否成功都会返回
     */
    @After("execution(* org.xiji.Calculation.*(..))")
    public void after(JoinPoint joinPoint)
    {
        System.out.println("==========================");
        System.out.println(joinPoint.getTarget());
        System.out.println("Aop后置处理器");
        System.out.println("after");
        System.out.println("==========================");
    }

    /**
     *
     * 返回处理器
     */
    @AfterReturning(pointcut = "execution(* org.xiji.Calculation.*(..))",returning = "returning")
    public void afterReturning(JoinPoint joinPoint,Object returning)
    {
        System.out.println("==========================");
        System.out.println(returning.toString());
        System.out.println(joinPoint.getTarget());
        System.out.println("Aop返回处理器");
        System.out.println("afterReturning");
        System.out.println("==========================");
    }

    /**
     * 异常处理器
     */
    @AfterThrowing(pointcut = "execution(* org.xiji.Calculation.*(..))",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint,Throwable throwable)
    {
        System.out.println("==========================");
        System.out.println(throwable.getMessage());
        System.out.println(joinPoint.getTarget());
        System.out.println("Aop异常处理器");
        System.out.println("afterThrowing");
        System.out.println("==========================");
    }


    /**
     * 定义切点
     */
    @Pointcut("execution(* org.xiji.Calculation.*(..))")
    public void pointCut()
    {

    }


    /**
     * 环绕通知
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint)
    {
        Object result = null;
        try {
            System.out.println("环绕通知前");
            result = joinPoint.proceed();
            System.out.println("result = " + result);
            System.out.println("环绕通知后");
        } catch (Throwable throwable) {
            System.out.println("环绕通知异常");
            throwable.printStackTrace();
        }finally {
            System.out.println("无论结果好坏必然运行");
        }
        return result;
    }
}

xml自定义AOP

xml文件中的内容

注:开启包扫描,注入切点,配置aop,配置前置方法,或其他的等等

        并且注入的切面类不需要加上@Aspect@Before注解,需要加入@Component

<?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:context="http://www.springframework.org/schema/context"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd

      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <!--配置包扫描-->
    <context:component-scan base-package="org.xiji"/>

    <aop:config>
        <aop:aspect ref="pointCutAop" >
            <!--配置前置-->
            <aop:before method="before" pointcut="execution(* org.xiji.Calculation.*(..))"></aop:before>
        </aop:aspect>
    </aop:config>

    <!--导入aop切点-->
    <bean id="pointCutAop" class="org.xiji.PointCutAop">

    </bean>

</beans>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值