当前位置: 首页 > news >正文

简述 AOP 动态代理

一、AopAutoConfiguration 源码:

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Advice.class)static class AspectJAutoProxyingConfiguration {@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",matchIfMissing = false)static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)static class CglibAutoProxyConfiguration {}}@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.aspectj.weaver.Advice")@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",matchIfMissing = true)static class ClassProxyingConfiguration {ClassProxyingConfiguration(BeanFactory beanFactory) {if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}}}}
  1. CglibAutoProxyConfiguration 类 matchIfMissing = true,所以默认使用 cglib 动态代理
  2. application.properties 里配置如下:spring.aop.auto=false,整个 AOP 都不会生效了
  3. application.properties 里配置如下:spring.aop.proxy-target-class=false,使用 jdk 动态代理

JDK 动态代理的限制在于,它只能代理实现了接口的类,如果一个类没有实现任何接口,JDK 动态代理就无法代理它,这是因为 JDK 动态代理是基于接口的代理,它生成的代理对象会实现指定接口,然后通过该接口来调用被代理类的方法。

需要注意的是,如果接口有多个实现类,并且你使用 @Autowired 注解注入时, Spring 会抛出异常,因为它无法确定应该注入哪个实现类的代理对象,在这种情况下,你需要明确指定要注入的实现类,可以使用 @Qualifier 注解或者在实现类上使用 @Primary 注解来解决这个问题

二、不使用 springboot,手动写 JDK 动态代理案例

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public interface MyInterface {void myMethod();
}public class MyInterfaceImpl implements MyInterface {public void myMethod() {System.out.println("Real object's method is called.");}
}public class MyInvocationHandler implements InvocationHandler {private MyInterface target;public MyInvocationHandler(MyInterface target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Proxy object's method is called before real object's method.");Object result = method.invoke(target, args);System.out.println("Proxy object's method is called after real object's method.");return result;}
}public class Main {public static void main(String[] args) {MyInterface realObject = new MyInterfaceImpl();MyInvocationHandler handler = new MyInvocationHandler(realObject);MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(MyInterface.class.getClassLoader(),new Class[]{MyInterface.class},handler);proxyObject.myMethod();}
}

在JDK动态代理中,代理对象实现了指定接口,并且在运行时动态生成代理实例。被代理的类必须实现至少一个接口,而代理对象会实现这个接口,并且在方法调用时会委托给InvocationHandler中的逻辑

在这个例子中,proxyObject是MyInterface接口的代理对象。代理对象实现了MyInterface接口,并且在invoke方法中执行了额外的逻辑。当proxyObject.myMethod()被调用时,代理对象会先执行invoke方法中的逻辑,然后再调用MyInterfaceImpl实现类的myMethod方法

三、不使用 springboot,手动写 CGLIB 动态代理案例

CGLIB(Code Generation Library)是一个功能强大的字节码生成库,它可以在运行时动态生成类的子类,常用于代理那些没有实现接口的类。以下是一个简单的CGLIB动态代理的使用案例:

  1. pom 文件
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
  1. 然后,考虑以下的被代理类 UserService:
public class UserService {public void saveUser() {System.out.println("Saving user...");}
}
  1. 现在,我们会使用CGLIB为它生成一个代理对象,并在方法调用前后添加额外的逻辑:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class UserServiceProxy implements MethodInterceptor {public Object createProxy(Object target) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("Before method execution");Object result = methodProxy.invokeSuper(proxy, args);System.out.println("After method execution");return result;}public static void main(String[] args) {UserServiceProxy userServiceProxy = new UserServiceProxy();UserService userServiceProxyInstance = (UserService) userServiceProxy.createProxy(new UserService());userServiceProxyInstance.saveUser();}
}
  1. 在上述代码中,MethodInterceptor 接口用于定义拦截器的逻辑。在 intercept
    方法中,我们在方法调用前后添加了额外的逻辑。Enhancer 类用于生成代理类,它设置了被代理类的父类和拦截器。createProxy
    方法接受一个目标对象,返回一个代理对象。

    运行上述代码会输出以下结果:

Before method execution
Saving user...
After method execution

相关文章:

简述 AOP 动态代理

一、AopAutoConfiguration 源码&#xff1a; Configuration(proxyBeanMethods false) ConditionalOnProperty(prefix "spring.aop", name "auto", havingValue "true", matchIfMissing true) public class AopAutoConfiguration {Configur…...

机器学习基础之《分类算法(8)—随机森林》

一、什么是集成学习方法 1、定义 集成学习通过建立几个模型组合的来解决单一预测问题。它的工作原理是生成多个分类器/模型&#xff0c;各自独立地学习和作出预测。这些预测最后结合成组合预测&#xff0c;因此优于任何一个单分类的做出预测 谚语&#xff1a;三个臭皮匠顶个诸…...

Python数据攻略-Pandas进行CSV和Excel文件读写

在数据分析的世界里,能够读取和写入不同格式的文件是一项基本而重要的技能。CSV(逗号分隔值)和Excel是两种常见的数据存储格式。它们在商业、科研、教育等多个领域都有广泛应用。 文章目录 读取CSV文件`pd.read_csv()` 文件读取函数的基本用法`DataFrame.to_csv()` 数据写入…...

lv7 嵌入式开发-网络编程开发 13 UNIX域套接字

1 UNIX 域流式套接字 本地地址 struct sockaddr_un {unsigned short sun_family; /* 协议类型 */char sun_path[108]; /* 套接字文件路径 */ };UNIX 域流式套接字的用法和 TCP 套接字基本一致&#xff0c;区别在于使用的协议和地址不同 UNIX 域流式套接字服务器端…...

blender光照系统设置

0&#xff09;Viewport Shading设置里面的Lighting下面的参数&#xff1a; Scene Lights,Scene World - Scene Lights是指在渲染模式下是否使用场景中的灯光对象来照亮物体。 - Scene World是指在渲染模式下是否使用场景中的世界设置来作为背景和环境光。如果关闭该选项&#…...

华为云云耀云服务器L实例评测|基于canal缓存自动更新流程 SpringBoot项目应用案例和源码

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到各种问题&#xff0c;在解决问题的过程中学到不少和运维相关的知识。 在之前的博客中&#xff0c;介绍过canal的安装和配置&#xff0c;参考博客 拉取创建canal镜像配置相关参数 & …...

vue3 中使用echarts图表——柱状图

柱状图是比较常用的图形结构&#xff0c;所以我先收集一些精美的柱状图 一、柱状图&#xff1a;设置圆角和颜色 <template><div class"box" ref"chartDom"></div> </template> <script setup> import { ref, onMounted } fr…...

基于Java的家政公司服务平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

深入了解 PostgreSQL:功能、特性和部署

PostgreSQL&#xff0c;通常简称为Postgres&#xff0c;是一款强大且开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它在数据存储和处理方面提供了广泛的功能和灵活性。本文将详细介绍 PostgreSQL 的功能、特性以及如何部署和使用它。 什么是 PostgreSQ…...

平台项目列表页实现(二)

这里写目录标题 一、顶部盒子设计1. 顶部盒子包含项目列表和添加项目、退出登录2个按钮 二、项目列表盒子设计三、添加项目盒子设计四、退出登录功能实现五、路由导航守卫实现六、展示项目信息七、bug修复1、当项目名称太长或者项目负责人太长&#xff0c;需要一行展示&#xf…...

osg实现鼠标框选

目录 1. 需求的提出 2. 具体实现 2.1. 禁止场景跟随鼠标转动 2.2. 矩形框前置绘制 3. 附加说明 3.1. 颜色设置说明 3.2.矩形框显示和隐藏的另一种实现 1. 需求的提出 有时需要在屏幕通过按住键盘上的某个键如Ctrl键且按住鼠标左键&#xff0c;拖出一个矩形&#xff0c;实现框…...

电路原理解题笔记(一)

文章目录 贼基础的知识等效电阻基尔霍夫电流定律电阻电路的一般分析支路电流法节点电压法回路电流法 电路定理叠加定理戴维宁等效电路诺顿等效电路求某电阻值为多少可吸收最大功率。吸收、释放功率 第一个月&#xff0c;对应猴博士的一到五课时。 贼基础的知识电阻电路的等效变…...

分享几个优秀开源免费管理后台模版,建议收藏!

大家好&#xff0c;我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面&#xff0c;帮助大家快速搭建前端页面。为什么要用模板&#xff1f;道理很简单&#xff0c;原因是方便我们快速开发。我们不应该花太多的时间在页面调整上&#xff0c;而应该把精力放在核心逻辑和…...

BFS模板:844. 走迷宫

给定一个 nmnm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 00 或 11&#xff0c;其中 00 表示可以走的路&#xff0c;11 表示不可通过的墙壁。 最初&#xff0c;有一个人位于左上角 (1,1)(1,1) 处&#xff0c;已知该人每次可以向上、下、左、右任意…...

re学习(37)DASCTF 2023 0X401七月暑期挑战赛 controflow

程序通过改变栈里面的返回地址来控制程序的控制流 从而达到混淆的效果 左侧有许多被hook的函数 在每个函数开头设置断点 然后观察程序的运行流程 会发现输入的数据会进行 异或 相加 异或 相减 相乘 异或等操作 要注意部分运算的索引是 从[10]开始的 具体思路参考&#xf…...

数字IC前端学习笔记:数字乘法器的优化设计(进位保留乘法器)

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 阵列乘法器设计中限制乘法器速度的是随着数据位宽而迅速增大的串行进位链&#xff0c;如果使用进位保留加法器&#xff0c;则可以避免在设计中引入较长时间的等待&…...

prority_queue的学习

优先级队列&#xff08;Priority Queue&#xff09;是一种抽象数据类型&#xff0c;它类似于普通的队列或堆栈&#xff0c;但每个元素都有一个关联的优先级&#xff0c;这个优先级决定了元素在队列中的位置和被访问的顺序。在优先级队列中&#xff0c;具有最高优先级的元素通常…...

【vue3】toRef与toRefs的使用,toRef与ref的区别

假期第四篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 1、toRef与toRefs 创建一个ref对象&#xff0c;其value值指向另一个对象中的某个属性 语法&#xff1a;const name toRef&#xff08;person,‘name’&#xf…...

信息论基础第二章部分习题

2.5 证明若H(Y|X)0&#xff0c;则Y是X的函数 若 H ( Y ∣ X ) 0 H(Y|X) 0 H(Y∣X)0&#xff0c;意味着在已知 X X X 的条件下&#xff0c; Y Y Y 的不确定性为零&#xff0c;即给定 X X X 的值&#xff0c;我们完全确定了 Y Y Y 的值。这表明 Y Y Y 的取值完全由 X X…...

信息化发展73

数字经济 数字经济是继农业经济、工业经济之后的更高级经济形态。从本质上看&#xff0c;数字经济是一种新的技术经济范式&#xff0c;它建立在信息与通信技术的重大突破的基础上&#xff0c;以数字技术与实体经济融合驱动的产业梯次转型和经济创新发展的主引擎&#xff0c;在…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

Python常用模块:time、os、shutil与flask初探

一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...

深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”

深入浅出JavaScript中的ArrayBuffer&#xff1a;二进制数据的“瑞士军刀” 在JavaScript中&#xff0c;我们经常需要处理文本、数组、对象等数据类型。但当我们需要处理文件上传、图像处理、网络通信等场景时&#xff0c;单纯依赖字符串或数组就显得力不从心了。这时&#xff…...