Spring AOP使用

Spring AOP是什么?

AOP(面向切面编程):将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为"切面"(Aspect),便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性;

在Spring AOP中,切面由切点(Pointcut)和通知(Advice)组成。切点是一个表达式,用于匹配哪些方法需要被横切,通知是在切点位置执行的代码,表示横切逻辑。

++切点表达式配置语法:++

execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))

execution(public void com.apesource.service.ServiceImp.findAll())

  1. 修饰符可以省略代表任意 execution(返回值 包名称.类名称.方法名称(参数列表))
  2. 返回值可以使用"*"代表任意 execution(* 包名称.类名称.方法名称(参数列表))
  3. 包名可以使用"*"代表任意名称 execution(* *.*.*.类名称.方法名称(参数列表))
  4. 包名可以使用".."代表任意个数 execution(* *...类名称.方法名称(参数列表))
  5. 类名与方法名可以使用"*"代表任意 execution(* *...*.*(参数列表))
  6. 参数列表可以使用".."代表任意个数任意类型 execution(* *...*.*(..))

如果有参数 int======>int String===>java.lang.String

++Spring AOP提供了几种常见的通知类型,包括:++

  • 前置通知(Before):在方法执行前执行的逻辑
  • 后置通知(After):在方法执行后执行的逻辑
  • 返回通知(After-returning):在方法成功返回后执行的逻辑
  • 异常通知(After-throwing):在方法抛出异常后执行的逻辑
  • 环绕通知(Around):在方法执行前后都可以执行的逻辑,可以控制目标方法的执行流程

Spring AOP 基于动态代理实现:

  • 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象;
  • 如果被代理的对象,没有实现某个接口, Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理;

Spring AOP可以通过注解或XML配置的方式来定义切点和通知,并且可以与Spring的IOC容器无缝集成,使得切面和目标对象的创建和管理变得更加简单。

1⃣️XML

1.添加依赖:

java 复制代码
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.28</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

2.创建切面类:

java 复制代码
public class LoggerUtil {
    //前置通知
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    public Object arroundMethod(ProceedingJoinPoint pjp){
        Object obj = null;
        try {
            //环绕通知---前置通知
            System.out.println("环绕通知---前置通知");
            Object[] objs = pjp.getArgs();
            obj = pjp.proceed(objs);
            //环绕通知---返回通知
            System.out.println("环绕通知---返回通知");
        } catch (Throwable throwable) {
            //环绕通知---异常通知
            System.out.println("环绕通知---异常通知");
            throwable.printStackTrace();
        } finally {
            //环绕通知---后置通知
            System.out.println("环绕通知---后置通知");
        }
        return obj;
    }
}

3.配置XML:

XML 复制代码
    <!--开启aop配置-->
    <aop:config>
        <!--切面-->
        <aop:aspect id="mian" ref="loggerUtil">
            <!--切点-->            
            <aop:pointcut id="dian" expression="execution(* *...*.*(..))"/>
            <!--通知-->
            <aop:before method="beforeMethod" pointcut-ref="dian"></aop:before>
            <aop:after-returning method="afterRrturnMethod" pointcut-ref="dian"></aop:after-returning>
            <aop:after-throwing method="throwMethod" pointcut-ref="dian"></aop:after-throwing>
            <aop:after method="afterMethod" pointcut-ref="dian"></aop:after>
            <aop:around method="arroundMethod" pointcut-ref="dian"></aop:around>
        </aop:aspect>
    </aop:config>

2⃣️注解

1.添加依赖:

java 复制代码
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.28</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

2.创建切面类:

java 复制代码
@Component
@Aspect//切面
//@EnableAspectJAutoProxy 
public class LoggerUtil {
    //切点
    @Pointcut(value="execution(* com.apesource.service.*.*(..))")
    public void dian(){}
    
    //前置通知
//    @Before("dian()")
    public void beforeMethod(){
        System.out.println("前置通知=====>"+new Date());
    }
    //返回通知
//    @AfterReturning("dian()")
    public void afterRrturnMethod(){
        System.out.println("返回通知=====>"+new Date());
    }
    //异常通知
//    @AfterThrowing("dian()")
    public void throwMethod(){
        System.out.println("异常通知=====>"+new Date());
    }
    //后置通知
//    @After("dian()")
    public void afterMethod(){
        System.out.println("后置通知=====>"+new Date());
    }

    //环绕通知
    @Around("dian()")
    public Object arroundMethod(ProceedingJoinPoint point){
        Object returnObj = null;//执行切点方法
        try {
            System.out.println("环绕通知====>前置通知");
            //切点
            Object[] obj = point.getArgs();//切点方法的参数
            returnObj = point.proceed(obj);
            System.out.println("环绕通知====>返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知====>异常通知");
        } finally {
            System.out.println("环绕通知====>后置通知");
        }
        return returnObj;//切点方法的返回值
    }
}

3.配置XML:(也大可不配直接注解)

XML 复制代码
  <!--aop的自动代理 @EnableAspectJAutoProxy可以替换标签-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
相关推荐
一只叫煤球的猫25 分钟前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9651 小时前
tcp/ip 中的多路复用
后端
bobz9651 小时前
tls ingress 简单记录
后端
皮皮林5512 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友2 小时前
什么是OpenSSL
后端·安全·程序员
bobz9652 小时前
mcp 直接操作浏览器
后端
前端小张同学5 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook5 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康6 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在6 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net