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>
相关推荐
一个诺诺前行的后端程序员28 分钟前
springcloud微服务实战<1>
spring·spring cloud·微服务
IT毕设梦工厂1 小时前
计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战
java·spring boot·python·django·毕业设计·源码·课程设计
Ylucius2 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
凡人的AI工具箱2 小时前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
是店小二呀2 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
七夜zippoe2 小时前
分布式系统实战经验
java·分布式
canonical_entropy2 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
是梦终空2 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
落落落sss2 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
码爸2 小时前
flink doris批量sink
java·前端·flink