简述 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

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

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

相关文章

【数据结构】排序算法(二)—>冒泡排序、快速排序、归并排序、计数排序

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.冒泡排序 2.快速排序 2.1Hoare版 2.2占…

C++入门

一、C关键字 C总计63个关键字&#xff0c;C语言32个关键字。 二、命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存 在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称…

谁“动”了我的信息?

通信公司“内鬼” 批量提供手机卡 超6万张手机卡用来发涉赌短信 2023年10月2日&#xff0c;据报道2022年12月&#xff0c;湖北省公安厅“雷火”打击整治治安突出问题专项行动指挥部研判发现&#xff0c;有人在湖北随州利用虚拟拨号设备GOIP发出大量赌博短信。随州市公安局研判…

蓝桥等考Python组别十三级004

第一部分:选择题 1、Python L13 (15分) 运行下面程序,输出的结果是( )。 t = (0, 1, 2, 3, 4) print(t[3]) 1234正确答案:C 2、Python L13 (15分) 运行下

【最新】如何在CSDN个人主页左侧栏添加二维码?侧边推广怎么弄?

目录 引言 效果展示 步骤讲解 引言 当你决定在CSDN上展示自己的技术才能和项目时&#xff0c;&#x1f4a1; 将你的个人主页变得更炫酷和引人注目是必不可少的&#xff01;在这篇博客中&#xff0c;我们将向你揭开神秘的面纱&#xff0c;教你如何在CSDN个人主页的左侧栏上添…

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型

RabbitMQ集群搭建详细介绍以及解决搭建过程中的各种问题——实操型 1. 准备工作1.1 安装RabbitMQ1.2 简单部署搭建设计1.3 参考官网 2. RabbitMQ 形成集群的方法3. 搭建RabbitMQ集群3.1 部署架构3.2 rabbitmq集群基础知识3.2.1 关于节点名称&#xff08;标识符&#xff09;3.2.…

Java常见API---split()

package daysreplace;public class SplitTest {public static void main(String[] args) {String str"武汉市|孝感市|长沙市|北京市|上海市";String[] array str.split("\\|");System.out.println(array[0]);System.out.println(array[1]);System.out.pri…

解决recovery页面反转的问题

1.前言 在android 10.0的系统rom定制化开发工作中&#xff0c;在系统中recoverv的页面也是相关重要的一部分&#xff0c;在系统recovery ta升级等功能&#xff0c;都是需要recoverv功能的&#xff0c;在某些产品定制化中 在recovery的时候&#xff0c;发现居然旋转了180度&…

javaee thymeleaf简介

thymeleaf 使用thymeleaf可以实现动静分离&#xff0c;jsp页面是无法直接用浏览器打开的&#xff0c;使用了thymeleaf后&#xff0c;页面是html格式&#xff0c;可以直接用浏览器打开&#xff0c;这样可以方便测试人员进行测试。

【C++】一文带你走入vector

文章目录 一、vector的介绍二、vector的常用接口说明2.1 vector的使用2.2 vector iterator的使用2.3 vector空间增长问题2.4 vector 增删查改 三、总结 ヾ(๑╹◡╹)&#xff89;" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)&#xff89;" 一、vector的介绍 vector…

golang gin——文件上传(单文件,多文件)

文件上传 单文件上传 从form-data获取文件 package uploadimport ("github.com/gin-gonic/gin""net/http" ) // 单文件上传&#xff0c;多文件上传 func Upload(c *gin.Context) {file, _ : c.FormFile("file") // file为字段名dst : "…

背包问题学习笔记-混合背包问题

题意描述&#xff1a; 有 N 种物品和一个容量是 V 的背包。物品一共有三类&#xff1a;第一类物品只能用1次&#xff08;01背包&#xff09;&#xff1b; 第二类物品可以用无限次&#xff08;完全背包&#xff09;&#xff1b; 第三类物品最多只能用 si 次&#xff08;多重背包…

nodejs开发环境搭建

Nodejs是一个开源的、跨平台JavaScript运行时环境&#xff0c;其使用V8引擎对JavaScript脚本执行解释&#xff0c;在前后端分离的应用架构设计中&#xff0c;其既能支持web页面服务应用的开发、也能支持后端接口服务应用的开发&#xff0c;类似于Java语言的J2EE运行时环境&…

安装matplotlib__pygame,以pycharm调入模块

安装pip 安装matplotlib 安装完毕&#xff0c;终端输入pip list检查 导入模块出现bug&#xff0c;发现不是matplotlib包的问题&#xff0c;pycharm版本貌似不兼容&#xff0c;用python编辑器可正常绘图&#xff0c;pygame也可正常导入。 ​​​​​​​ pycharm版本问题解决 终…

MarqueeView - 跑马灯

官网 https://github.com/sunfusheng/MarqueeView 项目简介 俗名&#xff1a;可垂直跑、可水平跑的跑马灯&#xff1b; 学名&#xff1a;可垂直翻、可水平翻的翻页公告 Gradle compile com.sunfusheng:MarqueeView:<latest-version> 属性 Attribute 属性 Descrip…

Java开发一些偏冷门的面试题

文章目录 1.进程间的通信&#xff0c;线程间的通信首先可以先回答进程、线程和协程关于线程和进程通信 2.MySQL中的缓存情况&#xff0c;以及缓存命中率查询 主要从别人的面经那里看来的&#xff0c;以及自己被问住的一些面试题。 拿出来给自己做记录&#xff0c;也顺便给大家做…

【Spring笔记02】Spring中的IOC容器和DI依赖注入介绍

这篇文章&#xff0c;主要介绍一下Spring中的IOC容器和DI依赖注入两个概念。 目录 一、IOC控制反转 1.1、什么是IOC 1.2、两种IOC容器 &#xff08;1&#xff09;基于BeanFactory的IOC容器 &#xff08;2&#xff09;基于ApplicationContext的IOC容器 二、DI依赖注入 2.…

stm32-SPI协议

SPI协议详解&#xff08;图文并茂超详细&#xff09; SPI通讯协议 于是我们想有没有更好一点的串行通讯方式&#xff1b;相比较于UART&#xff0c;SPI的工作方式略有不同。 SPI是一个同步的数据总线&#xff0c;也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和…

RT1 RT2 RTX() 学习

RT-1&#xff1a; 初生代的 ‘视觉-语言-动作模型’ 作品 RT-2: RT1使用130k条机器人遥操作数据训练&#xff0c;展示出了其处理多种任务的能力和很强的泛化能力。但其通用性仍受限于数据集的大小。 若想要得到一个表现出当前LLMs能力的机器人大模型&#xff0c;收集数以亿计…

MySQL中的 增 删 查 改(CRUD)

目录 新增 insert into 表名 value(数据&#xff0c;数据),.......&#xff1b; insert into 表名&#xff08;列1&#xff0c;列2.....&#xff09; value(数据&#xff0c;数据),.......&#xff1b; datatime 类型的数据如何插入&#xff1f; 查询 select * from 表名…