Spring AOP 理解与使用

1.前置知识

动态代理

Java 动态代理作用是什么? - 知乎

2.AOP基本概念

        AOP面向切面编程,可以不修改源代码进行方法增强,AOP是OOP(面向对象编程)的延续,主要用于日志记录、性能统计、安全控制、事务处理等方面。它是基于代理设计模式,而代理设计模式又分为静态代理和动态代理,静态代理比较简单就是一个接口,分别由一个真实实现和一个代理实现,而动态代理分为基于接口的JDK动态代理和基于类的cglib的动态代理,咱们正常都是面向接口开发,所以AOP使用的是基于接口的JDK动态代理。

  • 连接点 Joinpoint :在程序的整个执⾏流程中,可以织⼊切⾯的位置。⽅法的执⾏前后,异常抛出之后等位置
  • 切点 Pointcut: 在程序执⾏流程中,真正织⼊切⾯的⽅法。(⼀个切点对应多个连接点)。
  • 通知 Advice:通知⼜叫增强,就是具体你要织⼊的代码。 通知包括: 前置通知 后置通知 环绕通知 异常通知 最终通知。
  • 切⾯ Aspect: 切点 + 通知就是切⾯。
  • 织⼊ Weaving: 把通知应⽤到⽬标对象上的过程。
  • 代理对象 Proxy: ⼀个⽬标对象被织⼊通知后产⽣的新对象。 ⽬标对象 Target: 被织⼊通知的对象

3.切入点表达式

execution([访问控制权限修饰符] 返回值类型 [全限定类名]⽅法名(形式参数列表) [异常])

  • 访问控制权限修饰符: 可选项。 没写,就是4个权限都包括。 写public就表示只包括公开的⽅法;
  • 返回值类型: 必填项。 * 表示返回值类型任意;
  • 全限定类名: 可选项。 两个点“..”代表当前包以及⼦包下的所有类。 省略时表示所有的类;
  • ⽅法名: 必填项。 *表示所有⽅法。 set*表示所有的set⽅法;
  • 形式参数列表: 必填项 。表示没有参数的⽅法 (..) 参数类型和个数随意的⽅法 (*) 只有⼀个参数的⽅法 (*, String) 第⼀个参数类型随意,第⼆个参数是String的;
  • 异常: 可选项。 省略时表示任意异常类型

4.基于AspectJ的AOP注解式开发

4.1新建项目

4.2导入依赖
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.22</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.26</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.26</version>
        </dependency>
    </dependencies>
4.2 目标类
package service;

import org.springframework.stereotype.Service;

@Service
public class orderService {

    public void Buy(String car) {
        System.out.println("提车---->" + car + "...");
    }
}
4.3 切面类
package Aspect;

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

@Component
@Aspect
public class myAspect {

    @Pointcut("execution(* service.orderService*.*(..))")
    public void pointCut() {
    }


    @Before("pointCut()")
    public void myBefore() {
        System.out.println("前置通知执行了....");
    }

    @AfterReturning("pointCut()")
    public void myAfterReturning() {
        System.out.println("后置通知执行了...");
    }

    @Around("pointCut()")
    public Object myAround(ProceedingJoinPoint point) throws Throwable {
        System.out.println("环绕通知开始...");

        Object[] args = point.getArgs();
        if (null != args && args.length > 0) {
            // 原来参数
            Object arg = args[0];
            System.out.println("原来的参数:" + arg);

            // 更换参数
            args[0] = "比亚迪";
        }
        System.out.println("环绕通知结束...");

        return point.proceed(args);
    }

    @After("pointCut()")
    public void myAfter() {
        System.out.println("最终通知执行了...");
    }

}
4.4 spring配置文件
<?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
                           https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 扫描切面包   -->
    <context:component-scan base-package="Aspect"></context:component-scan>
    <!-- 扫描service包   -->
    <context:component-scan base-package="service"></context:component-scan>

    <!--     开启aop的自动代理添加完这句代码后所有带有@Aspect注解的都会生成一个代理对象   -->
    <aop:aspectj-autoproxy ></aop:aspectj-autoproxy>

</beans>
4.5 测试

5.通知类型&通知顺序

  • 前置通知:@Before ⽬标⽅法执⾏之前的通知
  • 后置通知:@AfterReturning ⽬标⽅法执⾏之后的通知
  • 环绕通知:@Around ⽬标⽅法之前添加通知,同时⽬标⽅法执⾏之后添加通知。
  • 异常通知:@AfterThrowing 发⽣异常之后执⾏的通知
  • 最终通知:@After 放在finally语句块中的通知

通知顺序

环绕通知 -> 前置通知 -> 目标方法 -> 后置通知 -> 最终通知

抛出异常通知随时可能执行,根据异常触发决定

6.设置增强类的加载优先级

有多个增强类对同一个方法进行增强,可设置增强类的加载优先级。

举例:比如上面有一个myAspect增强类对orderService类中的方法进行增强,现在有一个myAspect2增强类也对User类中的方法进行增强,那么哪个肯定是哪个增强类先被加载,则先执行哪个增强类。所以我们可以通过在增强类上面添加注解。

@Order(数字类型值)

进行设置类的加载优先级,数字类型值越小优先级越高

@Order(1)//加载优先级
@Component // 通过IOC中的注解将该类实例化到Spring容器
@Aspect // 声明切面类,并为本类生成代理对象
public class myAspect {
     .....省略.....   
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)是Spring框架的一个重要特性,它允许我们通过在应用程序中定义切入点和切面来实现横切关注点的模块化。 在传统的面向对象编程中,业务逻辑散布在应用程序的各个模块中,例如数据访问、日志记录、事务管理等。这些横切关注点会导致代码的重复和耦合性的增加。Spring AOP的目标就是将这些横切关注点从主业务逻辑中解耦出来,以便更好地维护和管理应用程序。 在Spring AOP中,我们通过使用Aspect(切面)、Join Point(连接点)、Advice(通知)、Pointcut(切入点)和Weaving(织入)等概念来实现横切关注点的管理。 - Aspect:切面是一个模块,它包含了一组横切关注点和通知的定义。 - Join Point:连接点是应用程序执行过程中可以插入切面的点,例如方法调用、方法返回等。 - Advice:通知是在连接点上执行的动作,它定义了在何时、何地和如何执行横切关注点。 - Pointcut:切入点是一个表达式,它定义了哪些连接点将被匹配到并执行通知。 - Weaving:织入是将切面应用到目标对象的过程,它可以在编译时、加载时或运行时进行。 通过使用Spring AOP,我们可以轻松地实现一些跨越多个模块的功能,例如日志记录、性能监控、事务管理等。它使得我们的代码更加模块化、可维护和可扩展。 需要注意的是,Spring AOP是基于代理的,通过动态代理技术实现切面的织入。它支持两种代理方式:JDK动态代理和CGLIB代理。默认情况下,如果目标对象实现了接口,则使用JDK动态代理;如果目标对象没有实现接口,则使用CGLIB代理。 总结来说,Spring AOPSpring框架中用于实现横切关注点的一种机制,它通过解耦业务逻辑和横切关注点,提高了代码的可维护性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值