Spring AOP(实现,动态原理)详解版

Spring AOP

  • 1.什么是AOP?
    • 1.1引入AOP依赖
    • 1.2编写AOP程序
  • 2.Spring AOP核⼼概念
    • 2.1 切点(Pointcut)
    • 2.2连接点(Join Point)
    • 2.3通知(Advice)
    • 2.4 切⾯(Aspect)
  • 3.通知类型
    • 3.1顺序
    • 3.2切⾯优先级 @Order
    • 3.3 ⾃定义注解 @MyAspect
  • 4. Spring AOP 原理
  • 5 动态代理怎么实现
    • 5.1 JDK 动态代理类实现步骤
      • 定义JDK动态代理类
      • InvocationHandler
      • Proxy
    • 5.2CGLIB 动态代理类实现步骤
  • 6.总结

1.什么是AOP?

AOP是⾯向切⾯编程切⾯。
什么是⾯向特定⽅法编程呢? ⽐如 登录校验拦截器, 就是对"登录校验"这类问题的统⼀处理. 所以, 拦截器也是AOP的⼀种应⽤. AOP是⼀种思想, 拦截器是AOP思想的⼀种实现. AOP是⼀种思想, 是对某⼀类事情的集中处理

1.1引入AOP依赖

在pom.xml⽂件中添加配置

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1.2编写AOP程序

记录Controller中每个⽅法的执⾏时间

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class TimeAspect {
/**
* 记录⽅法耗时
*/
@Around("execution(* com.example.demo.controller.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
//记录⽅法执⾏开始时间
long begin = System.currentTimeMillis();
//执⾏原始⽅法
Object result = pjp.proceed();
//记录⽅法执⾏结束时间
long end = System.currentTimeMillis();
//记录⽅法执⾏耗时
log.info(pjp.getSignature() + "执⾏耗时: {}ms", end - begin);
return result;
}

结论:
1.@Aspect: 标识这是⼀个切面类
2. @Around: 环绕通知, 在⽬标⽅法的前后都会被执⾏. 后⾯的表达式表⽰对哪些⽅法进⾏增强.
3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏

2.Spring AOP核⼼概念

2.1 切点(Pointcut)

切点(Pointcut), 也称之为"切⼊点"
Pointcut 的作⽤就是提供⼀组规则, 告诉程序对哪些⽅法来进⾏功能增强.
在这里插入图片描述

2.2连接点(Join Point)

满⾜切点表达式规则的⽅法, 就是连接点. 也就是可以被AOP控制的⽅法
以⼊⻔程序举例, 所有 com.example.demo.controller 路径下的⽅法, 都是连接点

2.3通知(Advice)

通知就是具体要做的⼯作, 指哪些重复的逻辑,也就是共性功能(最终体现为⼀个⽅法)
⽐如上述程序中记录业务⽅法的耗时时间, 就是通知.

2.4 切⾯(Aspect)

切⾯(Aspect) = 切点(Pointcut) + 通知(Advice)
通过切⾯就能够描述当前AOP程序需要针对于哪些⽅法, 在什么时候执⾏什么样的操作.
在这里插入图片描述

3.通知类型

3.1顺序

Spring中AOP的通知类型有以下⼏种:
• @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
• @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
• @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
• @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执⾏
• @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
在这里插入图片描述

程序正常运⾏的情况下, @AfterThrowing 标识的通知⽅法不会执⾏
@Around 标识的通知⽅法包含两部分, ⼀个"前置逻辑", ⼀个"后置逻辑".其中"前置逻辑" 会先于 @Before 标识的通知⽅法执⾏, “后置逻辑” 会晚于 @After 标识的通知⽅法执⾏
在这里插入图片描述

@Slf4j
@Aspect
@Component
public class AspectDemo {
//定义切点(公共的切点表达式)
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
private void pt(){}
//前置通知
@Before("pt()")
public void doBefore() {
//...代码省略
}
//后置通知
@After("pt()")
public void doAfter() {
//...代码省略
}
//返回后通知
@AfterReturning("pt()")
public void doAfterReturning() {
//...代码省略
}
//抛出异常后通知
@AfterThrowing("pt()")
public void doAfterThrowing() {
//...代码省略
}
//添加环绕通知
@Around("pt()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//...代码省略
}
}

当切点定义使⽤private修饰时, 仅能在当前切⾯类中使⽤, 当其他切⾯类也要使⽤当前切点定义时, 就需要把private改为public. 引⽤⽅式为: 全限定类名.⽅法名()

@Slf4j
@Aspect
@Component
public class AspectDemo2 {
//前置通知
@Before("com.example.demo.aspect.AspectDemo.pt()")
public void doBefore() {
log.info("执⾏ AspectDemo2 -> Before ⽅法");
}

3.2切⾯优先级 @Order

在这里插入图片描述
@Before 通知:数字越⼩先执⾏
@After 通知:数字越⼤先执⾏

@Order 控制切⾯的优先级, 先执⾏优先级较⾼的切⾯, 再执⾏优先级较低的切⾯, 最终执⾏⽬标⽅法.

3.3 ⾃定义注解 @MyAspect

在这里插入图片描述

import java.lang.annotation.ElementType;
2 import java.lang.annotation.Retention;
3 import java.lang.annotation.RetentionPolicy;
4 import java.lang.annotation.Target;
5
6 @Target(ElementType.METHOD)
7 @Retention(RetentionPolicy.RUNTIME)
8 public @interface MyAspect {
9 
10 }

1.@Target 标识了 Annotation 所修饰的对象范围, 即该注解可以⽤在什么地⽅.
常⽤取值:
ElementType.TYPE: ⽤于描述类、接⼝(包括注解类型) 或enum声明
ElementType.METHOD: 描述⽅法
ElementType.PARAMETER: 描述参数
ElementType.TYPE_USE: 可以标注任意类型
2. @Retention 指Annotation被保留的时间⻓短, 标明注解的⽣命周期

4. Spring AOP 原理

Spring AOP 是基于动态代理来实现AOP的
⽣活中的代理
• 艺⼈经纪⼈: ⼴告商找艺⼈拍⼴告, 需要经过经纪⼈,由经纪⼈来和艺⼈进⾏沟通.
• 房屋中介: 房屋进⾏租赁时, 卖⽅会把房屋授权给中介, 由中介来代理看房, 房屋咨询等服务.
实现
1.Subject: 业务接⼝类. 可以是抽象类或者接⼝(不⼀定有)
2. RealSubject: 业务实现类. 具体的业务执⾏, 也就是被代理对象.
3. Proxy: 代理类. RealSubject的代理.

5 动态代理怎么实现

1. JDK动态代理
2. CGLIB动态代理

5.1 JDK 动态代理类实现步骤

  1. 定义⼀个接⼝及其实现类(静态代理中的 HouseSubject 和 RealHouseSubject )
  2. ⾃定义 InvocationHandler 并重写 invoke ⽅法,在 invoke ⽅法中我们会调⽤⽬标⽅
    法(被代理类的⽅法)并⾃定义⼀些处理逻辑
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
    interfaces,InvocationHandler h) ⽅法创建代理对象

定义JDK动态代理类

实现 InvocationHandler 接⼝

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKInvocationHandler implements InvocationHandler {
//⽬标对象即就是被代理对象
private Object target;
public JDKInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Thro
// 代理增强内容
System.out.println("我是中介, 开始代理");
//通过反射调⽤被代理类的⽅法
Object retVal = method.invoke(target, args);
//代理增强内容
System.out.println("我是中介, 代理结束");
return retVal;
}
}

InvocationHandler

InvocationHandler 接⼝是Java动态代理的关键接⼝之⼀, 它定义了⼀个单⼀⽅法 invoke() , ⽤于处理被代理对象的⽅法调⽤.

public interface InvocationHandler {
/**
* 参数说明
* proxy:代理对象
* method:代理对象需要实现的⽅法,即其中需要重写的⽅法
* args:method所对应⽅法的参数
*/```bash
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

通过实现 InvocationHandler 接⼝, 可以对被代理对象的⽅法进⾏功能增强.

Proxy

Proxy 类中使⽤频率最⾼的⽅法是: newProxyInstance() , 这个⽅法主要⽤来⽣成⼀个代理对象

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
{
//...代码省略
}

5.2CGLIB 动态代理类实现步骤

  1. 定义⼀个类(被代理类)
  2. ⾃定义 MethodInterceptor 并重写 intercept ⽅法, intercept ⽤于增强⽬标⽅
    法,和 JDK 动态代理中的 invoke ⽅法类似
  3. 通过 Enhancer 类的 create()创建代理类

6.总结

  1. AOP是⼀种思想, 是对某⼀类事情的集中处理. Spring框架实现了AOP, 称之为SpringAOP
  2. Spring AOP常⻅实现⽅式有两种: 1. 基于注解@Aspect来实现 2. 基于⾃定义注解来实现, 还有⼀些更原始的⽅式,⽐如基于代理, 基于xml配置的⽅式, 但⽬标⽐较少⻅
  3. Spring AOP 是基于动态代理实现的, 有两种⽅式: 1. 基本JDK动态代理实现 2. 基于CGLIB动态代理实现. 运⾏时使⽤哪种⽅式与项⽬配置和代理的对象有关.
  4. 代理类只能用CGLIB,代理接口,CGLIB和JDK都可以。SpringBoot2.x以后默认使用CGLIB代理。用

spring.aop.proxy-target-class=false

来设置JDK代理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/344086.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Web后端开发(请求-简单参数)(一)

原始方式&#xff1a; 在原始的web程序中&#xff0c;获取请求参数&#xff0c;需要通过HttpServletRequest 对象手动获取。 RequestMapping("/simpleParam") public String simpleParam(HttpServletRequest request){//获取请求参数String name request.getParame…

html+CSS+js部分基础运用17

在图书列表中&#xff0c;为书名“零基础学JavaScript”和“HTML5CSS3精彩编程200例”添加颜色。&#xff08;请用class或style属性实现&#xff09;&#xff0c;效果如下图1所示&#xff1a; 图1 图书列表 Class和style的综合应用。&#xff08;1&#xff09;应用class的对象、…

使用wireshark分析tcp握手过程

开启抓包 tcpdump -i any host 127.0.0.1 and port 123 -w tcp_capture.pcap 使用telnet模拟tcp连接 telnet 127.0.0.1 123 如果地址无法连接&#xff0c;则会一直重试SYN包&#xff0c;各个平台SYN重试间隔并不一致&#xff0c;如下&#xff1a; 异常站点抓包展示&#xff…

抽象的java入门1.3.0

前言&#xff1a; 在1.2.0版本中我们介绍了public class hello {}并从中提取出两个新概 修饰符和作用域 public class hello {public static void main(String[] args) {System.out.println("Hello World");} } 正片&#xff1a; 这一期把剩余的内容刨析出来 pub…

Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战

Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战 目录 Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战 一、简单介绍 二、轮船人员获救预测实战 三、数据处理 1、导入数据 2、对缺失数据的列进行填充 3、属性转换&#xff0c;把某些列的字符串值…

【SkyWalking】启用apm-trace-ignore-plugin追踪忽略插件

背景 使用Agent采集追踪数据的时候&#xff0c;想排除某些路径&#xff0c;比如健康检查等&#xff0c;这样可以减少上报的数据&#xff0c;也可以去除一些不必要的干扰数据。 加载插件 在agent/optional-plugins目录中有个apm-trace-ignore-plugin-${version}.jar插件&…

WEB漏洞服务能提供哪些帮助

在数字化浪潮的推动下&#xff0c;Web应用程序已成为企业展示形象、提供服务、与用户进行交互的重要平台。然而&#xff0c;随着技术的飞速发展&#xff0c;Web应用程序中的安全漏洞也日益显现&#xff0c;成为网络安全的重大隐患。这些漏洞一旦被恶意攻击者利用&#xff0c;可…

AI高考大战,揭秘五大热门模型谁能问鼎数学之巅?

在高考前&#xff0c;我就有想法了&#xff0c;这一次让AI来做做高考题。就用国内的大模型&#xff0c;看哪家的大模型解题最厉害。 第一天考完&#xff0c;就拿到了2024高考数学2卷的电子版&#xff0c;这也是重庆市采用的高考试卷 这次选了5个AI工具&#xff0c;分别是天工&a…

Fatfs

STM32进阶笔记——FATFS文件系统&#xff08;上&#xff09;_stm32 fatfs-CSDN博客 STM32进阶笔记——FATFS文件系统&#xff08;下&#xff09;_stm32 文件系统怎样获取文件大小-CSDN博客 STM32——FATFS文件基础知识_stm32 fatfs-CSDN博客 021 - STM32学习笔记 - Fatfs文件…

React -- memo允许你的组件在 props 没有改变的情况下跳过重新渲染。

memo(Component, arePropsEqual?) 使用 memo 将组件包装起来&#xff0c;以获得该组件的一个 记忆化 版本。通常情况下&#xff0c;只要该组件的 props 没有改变&#xff0c;这个记忆化版本就不会在其父组件重新渲染时重新渲染。但 React 仍可能会重新渲染它&#xff1a;记忆化…

java 大型企业MES生产管理系统源码:MES系统与柔性化产线控制系统的关系、作用

MES定义为“位于上层的计划管理系统与底层的工业控制之间的面向车间层的管理信息系统”,它为操作人员/管理人员提供计划的执行、跟踪以及所有资源(人、设备、物料、客户需求等)的当前状态。 MES系统与柔性化产线控制系统的关系 MES&#xff08;制造执行系统&#xff09;是一种…

离散数学---树

目录 1.基本概念及其相关运用 2.生成树 3.有向树 4.最优树 5.前缀码 1.基本概念及其相关运用 &#xff08;1&#xff09;无向树&#xff1a;连通而且没有回路的无向图就是无向树&#xff1b; 森林就是有多个连通分支&#xff0c;每个连通分支都是树的无连通的无向图&…

pytorch构建模型训练数据集

pytorch构建模型训练数据集 pytorch构建模型训练数据集1.AlexNet:1.1.导入必要的库&#xff1a;1.2.数据预处理和增强&#xff1a;1.3.加载数据集&#xff1a;1.4.划分测试集和训练集&#xff1a;1.5.创建数据加载器&#xff1a;1.6.加载AlexNet模型&#xff1a;1.7.修改模型以…

训练营第三十一天 | 494.目标和474.一和零动态规划:完全背包理论基础518.零钱兑换II

494.目标和 力扣题目链接(opens new window) 难度&#xff1a;中等 给定一个非负整数数组&#xff0c;a1, a2, ..., an, 和一个目标数&#xff0c;S。现在你有两个符号 和 -。对于数组中的任意一个整数&#xff0c;你都可以从 或 -中选择一个符号添加在前面。 返回可以使…

mysql当前状态分析(show status)

文章目录 查看当前线程数据查询连接情况查询缓存相关查询锁相关查询增删改查执行次数查询DDL创建相关 SHOW STATUS 是一个在 MySQL 中用来查看服务器运行状态的命令。它可以帮助你了解服务器的当前性能&#xff0c;包括连接数、表锁定、缓冲区使用情况等信息。 查看当前线程数据…

电机专用32位MCU PY32MD310,Arm® Cortex-M0+内核

PY32MD310是一颗专为电机控制设计的MCU&#xff0c;非常适合用做三相/单相 BLDC/PMSM 的主控芯片。芯片采用了高性能的 32 位 ARM Cortex-M0 内核&#xff0c;QFN32封装。内置最大 64 Kbytes flash 和 8 Kbytes SRAM 存储器&#xff0c;最高48 MHz工作频率&#xff0c;多达 16 …

Vue2工程化

本节目标 工程化开发项目运行流程组件化组件注册自定义创建项目 工程化开发 基于构建工具的环境开发Vue Webpack的缺点 webpack的配置并不简单基础的配置雷同各公司缺乏统一标准 Vue CLI Vue CLI是Vue官方提供的一个全局命令工具帮助我们快速创建标准化的开发环境( 集成了w…

图解通用网络IO底层原理、Socket、epoll、用户态内核态······

LInux 操作系统中断 什么是系统中断 这个没啥可说的&#xff0c;大家都知道&#xff1b; CPU 在执行任务途中接收到中断请求&#xff0c;需要保存现场后去处理中断请求&#xff01;保存现场称为中断处理程序&#xff01;处理中断请求也就是唤醒对应的任务进程来持有CPU进行需要…

YOLOv10开源,高效轻量实时端到端目标检测新标准,速度提升46%

前言 实时目标检测在自动驾驶、机器人导航、物体追踪等领域应用广泛&#xff0c;近年来&#xff0c;YOLO 系列模型凭借其高效的性能和实时性&#xff0c;成为了该领域的主流方法。但传统的 YOLO 模型通常采用非极大值抑制 (NMS) 进行后处理&#xff0c;这会增加推理延迟&#…

gulimall-search P125 springboot整合elasticsearch版本冲突

一、问题 spring-boot.version 2.2.4.RELEASE,在gulimall-search pom.xml中添加elasticsearch.version 7.4.2后&#xff0c;发现出现如下问题&#xff1a;elasticsearch版本是springboot引入的6.8.6&#xff0c;没有变为7.4.2。 二、原因 在gulimall-search 的pom文件中&#…