SpringAOP

文章目录

AOP思想

​ AOP:面向切面编程,核心思想就是解耦。将每个方法/类中通用的逻辑剥离出来,封装成一个独立的模块,在程序运行期间自动将这些逻辑加入到业务代码中(织入)。从而实现业务逻辑与非业务逻辑之间的解耦

非业务逻辑包括:日志记录,性能统计,权限校验等一些与业务无关,但每个方法中都包含的逻辑

AOP可以做到在程序运行期间在不修改源代码的基础上对原有方法进行增强

SpringAOP

  1. 切面:封装通用的非业务逻辑的类
  2. 连接点:程序运行中所有可以插入切面的方法
  3. 切入点:实际被拦截的连接点
  4. 通知/增强:切面插入具体的方法后,所执行的逻辑
  5. 目标对象:被一个或多个切面所拦截和增强的,包含业务逻辑的原始对象
  6. 织入:将切面应用到目标对象,并创建代理对象

通知类型

  1. @Before:目标方法执行前执行

    除非这个通知抛出异常,否则不能阻止目标方法的执行

  2. @AfterReturning:目标方法执行完成并返回结果后执行执行

    目标方法内部抛出异常,这个通知不会执行

  3. @AfterThrowing:目标方法运行过程中,抛出异常时执行

    只有发生异常时才能触发,可以指定只拦截特定类型的对象

  4. @After:目标方法执行完成并返回结果后执行执行

    目标方法内部无论是否抛出异常,这个通知都会执行

  5. @Around:目标方法前后都会执行

    java 复制代码
    	@Around("execution(...)")
    										//只有@Around有这个参数
    public Object timeRecord(ProceedingJoinPoint proceedingJoinPoint){
    			//方法执行前...
       Object proceed=null;
            try{
               //执行目标方法,并接收返回值
               proceed= proceedingJoinPoint.proceed();
            }catch (Throwable throwable){
               //抛出异常时执行的逻辑...
            }
     			//方法执行后...
    	return proceed;
    }

注意:

  • @Around方法的返回值必须为Object,用于返回原始方法的返回值,否则原始方法执行完毕今后无法获取返回值。
  • 其他四种通知虽然不能接收ProceedingJoinPoint但是都可以接收一个JoinPoint参数,来获取目标方法的签名、方法名、参数列表等基本信息

执行顺序

@PointCut

将公共的切点表达式提取出来,用到时直接引用

java 复制代码
@Pointcut("execution(...)")
	public void pt(){} 

@Before("pt()")
...

引用其他切面类中的切点定义时,使用全限定类名.方法()名

切面优先级@Order

使用@Order控制不同切面的执行顺序,@Order接收一个整数,值越小,优先级越高。

最高优先级:Ordered.HIGHEST_PRECEDENCE

最低优先级:Ordered.LOWEST_PRECEDENCE

优先级越高,目标方法执行前越先执行,同时目标方法执行后,越后执行

切点表达式

execution()

复制代码
execution([权限修饰符] 返回值类型 [包名.类名.]方法名(参数类型) [抛出异常类型])
// execution(* com.example.demo..*(..))
  1. *:匹配任意单个元素,任意返回值/类名/方法名
  2. ..
    1. 包路径中:当前包及其所有子包
    2. 参数列表中:任意数量,任意类型的参数
  3. +:放在接口或类名后,表示匹配该类及其所有子类或实现类

@annotation

使用自定义注解+@annotation来描述一些无规则的切入点

  1. 编写自定义注解

    java 复制代码
    //表示为方法注解
    @Target(ElementType.METHOD)
    //注解的生命周期
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyAspect { }

    @Target常用取值

    ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明 ElementType.METHOD: 描述方法

    ElementType.PARAMETER: 描述参数

    ElementType.TYPE_USE: 可以标注任意类型

    @Retention描述注解的生命周期

    1. RetentionPolicy.SOURCE:表示注解仅存在于源代码中, 编译成字节码后会被丢弃(@Data)
    2. RetentionPolicy.CLASS:编译时注解. 表示注解存在于源代码和字节码中, 但在运行时会被丢弃
    3. RetentionPolicy.RUNTIME:运行时注解. 表示注解存在于源代码, 字节码和运行时中
  2. 使用@annotation切点表达式定义切点,只对@MyAspect生效

    java 复制代码
    @Before("@annotation(org.en.aop.aspect.MyAspect)")
        public void before(){
            log.info("method before-myaspect");
        }
  3. 在需要的方法上使用@MyAspect添加自定义注解

AOP同类内部方法调用失效

在同一个类中,方法A调用带有AOP注解的方法B,B的切面逻辑不会生效。因为是直接调用的目标对象本身,并没有经过代理对象

代理模式

提供一个代理类,在调用方法时不再直接对目标方法进行调用,而是通过调用代理类进行间接调用

  1. Subject: 业务接口类,抽象类或者接口,用于定义代理类的逻辑
  2. RealSubject: 业务实现类. 具体的业务执行, 也就是被代理对象.
  3. Proxy: 代理类. RealSubject的代理.

静态代理

程序运行之前,代理类的.class文件就已经存在

动态代理

不需要针对每个目标对象都创建一个代理对象,将创建代理对象的工作推迟到程序运行时由JVM实现。代理类是在程序运行时动态生成的


相关推荐
浩冉学编程2 小时前
微信小程序中基于java后端实现官方的文本内容安全识别msgSecCheck
java·前端·安全·微信小程序·小程序·微信公众平台·内容安全审核
A__tao2 小时前
JSON 转 Java 实体类工具(支持嵌套与注释解析)
java·python·json
zx2859634002 小时前
Laravel6.x新特性全解析
java·后端·spring
极光代码工作室2 小时前
基于SpringBoot的图书管理系统
java·springboot·web开发·后端开发
许彰午2 小时前
# 从OOM到根治的完整过程——导出大数据的应急、根因分析与游标方案
java·大数据·数据库·系统架构
上弦月-编程2 小时前
C语言指针超详细教程——从入门到精通(面向初学者)
java·数据结构·算法
ANnianStriver2 小时前
Java中的stream流的用法
java
不灭锦鲤2 小时前
网络安全学习第101天
学习
1104.北光c°2 小时前
【AI核心概念讲解】一口气搞懂 Agent:干翻传统后端!自主循环决策的秘密,ReAct 与 Plan-and-Execute 范式
java·人工智能·程序人生·ai·agent·react·智能体