Spring AOP概念

Spring AOP是什么?

Spring AOP是面向切面编程,他与OOP(面向对象编程)是相辅相成的。

在 OOP 中,以类作为程序的基本单元,而 AOP 中的基本单元是 Aspect(切面)。

在业务处理代码中,通常都有日志记录、性能统计、安全控制、事务处理、异常处理等操作。尽管使用 OOP 可以通过封装或继承的方式达到代码的重用,但仍然存在同样的代码分散到各个方法中。因此,采用 OOP 处理日志记录等操作,不仅增加了开发者的工作量,而且提高了升级维护的困难。为了解决此类问题,AOP 思想应运而生。AOP 采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段,再将这些抽取出来的代码应用到需要执行的地方。 这种横向抽取机制采用传统的 OOP 是无法办到的,因为 OOP 实现的是父子关系的纵向重用 。但是 AOP 不是 OOP 的替代品,而是 OOP 的补充 ,它们是相辅相成的。

Spring通知类型

环绕通知

环绕通知是在目标方法执行前和执行后实施增强,可以应用于日志记录、事务处理等。

前置通知

前置通知是在目标方法执行前实施增强,可应用于权限管理等。

后置返回通知

后置返回通知是在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等。

后置(最终)通知

后置通知是在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该通知,可应用于释放资源。

异常通知

异常通知是在方法抛出异常后实施增强,可以应用于异常处理、日志记录等。

引入通知

引入通知是在目标类中添加一些新的方法和属性,可以应用于修改目标类(增强类)。

举例

使用 Eclipse 创建一个名为 Myaspect 的 Dynamic Web Project,必要的 jar 已经复制到 WEB-INF/lib 目录中。在 src 目录中,创建一个名为 aspectj.dao 的包,并在该包中创建接口 catDao 和接口实现类 catDaoImpl。该实现类作为目标类,在切面类中对其所有方法进行增强处理。

复制代码
package aspectj.dao;

public interface catDao {
    public void eat();
    public void sleep();
    public void play();
}

package aspectj.dao;

import org.springframework.stereotype.Repository;

@Repository("catDao")
public class catDaoImp implements catDao {
    @Override
    public void eat() {
        System.out.println("小猫吃饭");
    }
    @Override
    public void sleep() {
        System.out.println("小猫睡觉");
    }
    @Override
    public void play() {
        System.out.println("小猫玩");
    }
}

在 src 目录中,创建一个名为 aspectj.annotation 的包,并在该包中创建切面类 MyAspect。在该类中,用 @Aspect 注解定义一个切面类,并通过定义方法表示切入点名称。在目标类每一个方法上,做切面,成消息和目标方法名称输出,完成方式和消息为:

前置通知:主人召唤小猫

后置通知:小猫自主活动

环绕开始:执行目标方法前,开启摄像头

环绕结束:执行目标方法后,关闭摄像头

java 复制代码
/**
 * 切面类,在此类中编写各种类型通知
 */
@Aspect //@Aspect 声明一个切面
@Component //@Component 让此切面成为 Spring 容器管理的 Bean
public class MyAspect {
    /**
     * 定义切入点,通知增强哪些方法。
     * "execution(* aspectj.dao.*.*(..))" 是定义切入点表达式,
     * 该切入点表达式的意思是匹配aspectj.dao包中任意的任意方法的执行。
     * 其中execution()是表达式的主体,第一个*表示返回类型,*代表所有类型;
     * aspectj.dao表示需要匹配的包名,后面第二个*表示类名,使用*代表匹配包中所有的类;
     * 第三个*表示方法名,使用*表示所有方法;后面(..)表示方法的参数,其中".."表示任意参数。
     * 另外,注意第一个*与包名之间有一个空格。
     */
    @Pointcut("execution(* aspectj.dao.*.*(..))")
    private void myPointCut() {
    }
    /**
     * 前置通知,使用 Joinpoint 接口作为参数获得目标对象信息
     */
    @Before("myPointCut()") //myPointCut()是切入点的定义方法
    public void before(JoinPoint jp) {
        System.out.print("前置通知:主人召唤小猫");
        System.out.println(",目标类对象:" + jp.getTarget()
                + ",被增强处理的方法:" + jp.getSignature().getName());
    }
    /**
     * 后置返回通知
     */
    @AfterReturning("myPointCut()")
    public void afterReturning(JoinPoint jp) {
        System.out.print("后置返回通知:" + "小猫自主活动");
        System.out.println(",被增强处理的方法:" + jp.getSignature().getName());
    }
    /**
     * 环绕通知
     * ProceedingJoinPoint 是 JoinPoint 子接口,代表可以执行的目标方法
     * 返回值类型必须是 Object
     * 必须有一个参数是 ProceedingJoinPoint 类型
     * 必须是 throws Throwable
     */
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //开始
        System.out.println("环绕开始:执行目标方法前,开启摄像头");
        //执行当前目标方法
        Object obj = pjp.proceed();
                //结束
        System.out.println("环绕结束:执行目标方法后,关闭摄像头");
        return obj;
    }
    /**
     * 异常通知
     */
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void except(Throwable e) {
        System.out.println("异常通知:" + "程序执行异常" + e.getMessage());
    }
    /**
     * 后置(最终)通知
     */
    @After("myPointCut()")
    public void after() {
        System.out.println("最终通知:模拟释放资源");
    }
}

此处要着重会使用Joinpoint接口作为参数获取目标对象信息

相关推荐
蕨蕨学AI6 分钟前
【Wolfram语言】45.2 真实数据集
java·数据库
Mr -老鬼17 分钟前
Rust适合干什么?为什么需要Rust?
开发语言·后端·rust
予枫的编程笔记20 分钟前
【Java集合】深入浅出 Java HashMap:从链表到红黑树的“进化”之路
java·开发语言·数据结构·人工智能·链表·哈希算法
ohoy26 分钟前
RedisTemplate 使用之Set
java·开发语言·redis
mjhcsp26 分钟前
C++ 后缀数组(SA):原理、实现与应用全解析
java·开发语言·c++·后缀数组sa
123445234 分钟前
Agent入门实战-一个题目生成Agent
人工智能·后端
IT_陈寒36 分钟前
Java性能调优实战:5个被低估却提升30%效率的JVM参数
前端·人工智能·后端
快手技术37 分钟前
AAAI 2026|全面发力!快手斩获 3 篇 Oral,12 篇论文入选!
前端·后端·算法
颜酱39 分钟前
前端算法必备:滑动窗口从入门到很熟练(最长/最短/计数三大类型)
前端·后端·算法
8***f39540 分钟前
Spring容器初始化扩展点:ApplicationContextInitializer
java·后端·spring