Spring之CGLIB和JDK动态代理底层实现

news2025/1/18 7:38:58

目录

CGLIB

使用示例-支持创建代理对象,执行代理逻辑

使用示例-多个方法,走不同的代理逻辑

JDK动态代理

使用示例-支持创建代理对象,执行代理逻辑


Spring会自动在JDK动态代理和CGLIB之间转换:

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

3、如果目标对象没有实现了接口,必须采用CGLIB库

本文主要讲解CGLIB和JDK动态代理的使用和底层原理

CGLIB

CGLIB动态代理是利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

使用示例-支持创建代理对象,执行代理逻辑

新建一个UserService类,这个类是目标类,后续会被代理

public class UserService {
	public void test() {
		System.out.println("userService execute test....");
	}
}

使用Enhancer类设置代理类UserService,设置代理逻辑,创建代理对象

public class CylTest {
	public static void main(String[] args) {
		UserService target = new UserService();

		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(UserService.class);

		//设置代理逻辑
		enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
			@Override
			public Object intercept(/*目标对象*/Object o,
                                    /*目标对象方法*/Method method,
                                    /*参数*/Object[] args,
                                    /*代理对象方法*/MethodProxy methodProxy) 
            throws Throwable {
				System.out.println("before");
				Object result = method.invoke(target, args);
				System.out.println("after");
				return result;
			}
		}});

        //创建代理对象=>类型是UserService,但却是代理对象
		UserService userService = (UserService) enhancer.create();
		userService.test();
	}
}

这个阶段会产生三个对象:

1.目标对象-targetUserService

2.负责创建代理对象的工厂对象enhancer

3.代理对象-proxyUserService

最终执行效果:

before

userService execute test....

after

使用示例-多个方法,走不同的代理逻辑

新建一个UserService类,设置两个方法

public void test() {
		System.out.println("userService execute test....");
	}

	public void a() {
		System.out.println("userService execute a....");
	}

在enhancer对象中设置两个代理逻辑,test方法走代理逻辑1,a方法走代理逻辑2

public static void main(String[] args) {
		UserService targetUserService = new UserService();

		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(UserService.class);

		//代理逻辑:1
		MethodInterceptor firstCallback = new MethodInterceptor() {
			@Override
			public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				System.out.println("before");
				Object result = method.invoke(targetUserService, args);
				System.out.println("after");
				return result;
			}
		};
		//代理逻辑:2
		NoOp secondCallback = NoOp.INSTANCE;

		enhancer.setCallbacks(new Callback[]{firstCallback, secondCallback});

		enhancer.setCallbackFilter(new CallbackFilter() {
			@Override
			public int accept(Method method) {
				//方法test执行=》firstCallback代理逻辑:1
				if (method.getName().equals("test")) {
					return 0;
				}
				//其他执行=》secondCallback代理逻辑:2
				return 1;
			}
		});

		UserService proxyUserService = (UserService) enhancer.create();
		System.out.println("执行proxyUserService.test:");
		proxyUserService.test();
		System.out.println("--------------------------------------------------------");
		System.out.println("执行proxyUserService.a:");
		proxyUserService.a();
	}

最终执行效果:

执行proxyUserService.test:

before

userService execute test....

after

--------------------------------------------------------

执行proxyUserService.a:

userService execute a....

JDK动态代理

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

使用示例-支持创建代理对象,执行代理逻辑

//接口
public interface UserInterface {
	void test();
	void a();
}
//实现类
public class UserService implements UserInterface {
	@Override
	public void test() {
		System.out.println("userService execute test....");
	}
	@Override
	public void a() {
		System.out.println("userService execute a....");
	}
}

使用Proxy.newProxyInstance创建一个代理接口,InvocationHandler制定代理逻辑

public class CylTest {
	public static void main(String[] args) {
		UserService targetUserService = new UserService();

		UserInterface proxyUserInterface = (UserInterface) Proxy.newProxyInstance(
				UserInterface.class.getClassLoader(),
				new Class[]{UserInterface.class},
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("before");
						Object result = method.invoke(targetUserService, args);
						System.out.println("after");
						return result;
					}
				});

		proxyUserInterface.test();
	}
}

最终执行效果:

before

userService execute test....

after

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

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

相关文章

基于51单片机智能鱼缸仿真LCD1602显示( proteus仿真+程序+设计报告+讲解视频)

基于51单片机智能鱼缸仿真LCD显示 1. 主要功能:2. 讲解视频:3. 仿真4. 程序代码5. 设计报告6. 设计资料内容清单&&下载链接资料下载链接: 基于51单片机智能鱼缸仿真LCD显示( proteus仿真程序设计报告讲解视频) 仿真图prot…

【Web】NewStarCTF 2022 题解(全)

目录 Week1 HTTP Head?Header! 我真的会谢 NotPHP Word-For-You Week2 Word-For-You(2 Gen) IncludeOne UnserializeOne ezAPI Week3 BabySSTI_One multiSQL IncludeTwo Maybe You Have To think More Week4 So Baby RCE BabySSTI_Two UnserializeT…

IDEA 安装、基本使用、创建项目

文章目录 下载基本使用修改颜色主题Keymap插件 创建项目创建模块新建 Java 类运行新建 Package打包 Jar运行 jar 包 查看文档 下载 官方下载地址:https://www.jetbrains.com/zh-cn/idea/download/?sectionmac 这里我下载 macOS 社区版,IDEA 2024.1 (C…

mPEG-Glutaramide Acid结合了聚乙二醇(PEG)和戊二酸(GAA)的性质

【试剂详情】 英文名称 mPEG-GAA,Methoxy PEG GAA, mPEG-Glutaramide Acid 中文名称 聚乙二醇单甲醚酰胺戊二酸, 甲氧基-聚乙二醇-戊二酰胺酸 外观性状 由分子量决定 分子量 400,600,2k,3.4k,5k&…

代码随想录算法训练营第五十七天 | 647. 回文子串、516. 最长回文子序列

代码随想录算法训练营第五十七天 | 647. 回文子串、516. 最长回文子序列 647. 回文子串题目解法 516. 最长回文子序列题目解法 动态规划总结链接感悟 647. 回文子串 题目 解法 题解链接 动态规划 class Solution { public:int countSubstrings(string s) {// dp[i][j]:表示…

[Java EE] 多线程(二): 线程的创建与常用方法(下)

2.3 启动一个线程–>start() 之前我们已经看到了如何通过重写run()方法来创建一个线程对象,但是线程对象被创建出来并不意味着线程就开始运行了. 覆写run方法是给线程提供了所要做的事情的指令清单创建线程对象就是把干活的人叫了过来.而调用start方法,就是喊一声"行…

Java处理CSV类库:OpenCSV

一:CSV简介 Comma-Separated Values(CSV), 因分隔符没有严格指定规范标准,可以使用逗号,也可以使用其他字符(如制表符\t、分号;等),所以CSV也称为 逗号分隔值或者字符分隔值。csv文件是使用纯文本来存储表…

【数据库】为什么要添加一个与业务无关的主键?

关注获取更多: 你是否想过,为什么mysql要设置一个自增的主键,或者使用uuid生成一个和业务无关的主键id,在数据库设计中,主键是用来唯一标识每一行数据的关键。通常情况下,我们会选择与业务相关的字段作为…

CMEF | 澳鹏Appen精彩亮相第89届中国国际医疗器械博览会

4月14日,为期四天的第89届中国国际医疗器械博览会(CMEF)盛大收官。如今,人们的健康需求在人口老龄化等一系列因素的影响下持续增长,这意味着卫生系统也面对着更多具有复杂健康需求的患者。信息化、数字化、智能化已经成…

Zynq学习笔记--数字视频帧以及同步信号

目录 1. 介绍 2. 重要概念 3. 仿真测试 4. 总结 1. 介绍 Zynq芯片,作为一款集成了高性能FPGA和ARM处理器的系统级芯片(SoC),为视频处理提供了强大的硬件支持。该芯片内置的丰富视频方面的IP模块,使得从事视频处理项目的开发者能够高效、…

PHP 使用 PHPMailer 发送电子邮件

1. PHPMailer 介绍 phpMailer 是一个非常强大的 php 发送邮件扩展包,可以设定发送邮件地址、回复地址、邮件主题、html邮件内容和上传附件等,使用起来非常方便。它目前有着有近 4 千万的下载量,是 PHP 开发者实现邮件发送功能的首选扩展包 它…

阅读小程序|基于微信阅读网站小程序的系统设计与实现(源码+数据库+文档)

目录 基于微信阅读网站小程序 一、前言 二、系统设计 三、系统功能设计 小程序端: 后台 管理员进入指定功能操作区之后可以管理图书订单。其页面见下图。管理员审核订单,查看订单是否支付,为购买图书的用户推送对应的章节。 管理员进…

西瓜书学习——第一、二章笔记

[] 什么是机器学习? 研究关于“学习算法”(一类能从数据中学习出其背后潜在规律的算法)的一门学科。 PS:深度学习指的是神经网络那一类学习算法,因此是机器学习的子集。 假设空间和版本空间 举个栗子:假设现已收集到某地区近几年的房价和学校数量数据&#xf…

【基础物理实验】【AFM虚拟实验】基于AFM的物质表面微观结构及力学性质表征仿真实验(下)【北京航空航天大学】

本次实验(上)见博客:【基础物理实验】【AFM虚拟实验】基于AFM的物质表面微观结构及力学性质表征仿真实验(上)【北京航空航天大学】 本次实验(中)见博客:【基础物理实验】【AFM虚拟实…

『哈哥赠书 - 51期』-『数字风控体系:设计与实践』

⭐️ 赠书 - 《数字风控体系:设计与实践》 ⭐️ 数字风控概述 从2007年开始到2014年左右,高速移动网络和智能手机迅速在大众中普及,开启了移动互联网时代。在这个背景下,企业的产品与服务也出现了两个重要的趋势。 第一个趋势是…

(十三)C++自制植物大战僵尸游戏多用户存档实现(二)

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/8UFMs UserData.h 在头文件中定义了枚举类型openUserDataReturnType,用于表示打开用户数据文件的返回状态。FileExistError表示文件存在但是打开错误,FileExistCorrect表示文件在且正确&#xff0…

活动理论的散点图

import pandas as pd import matplotlib.pyplot as plt# 假设您已经有一个名为 data.xlsx 的 Excel 文件 # 您可以使用以下代码读取数据# 读取 Excel 文件 try:data pd.read_excel(data.xlsx) except Exception as e:print(f"Error: {e}")# 假设您的数据包含以下列:…

2024 OceanBase开发者大会:专场论坛亮点抢先看

4 月 20 日,2024 OceanBase 开发者大会将在上海闵行区漕宝路 3199 号宝龙艾美酒店召开。 此次盛会专为开发者们量身打造,OceanBase诚挚邀请了来自不同行业的最佳实践用户、业界享有盛誉的技术专家,以及OceanBase数据库领域的精英们齐聚一堂。…

线程池学习(通俗易懂)

线程池 线程池是什么ThreadPoolExecutor模拟实现线程池结语 线程池是什么 假设我们要频繁的创建线程和销毁线程,但是创建线程和销毁线程是有成本的. 所以我们可以提前创建一批线程,后面需要使用的时候,直接拿就可以了,这就是线程池. 当线程不再使用的时候,就归还到池子里.为什…

软考131-上午题-【软件工程】-软件可靠性、可用性、可维护性

可靠性、可用性和可维护性是软件的质量属性,软件工程中,用 0-1 之间的数来度量。 0.66 66% 1、 可靠性 可靠性是指一个系统对于给定的时间间隔内、在给定条件下无失效运作的概率。 可以用 MTTF/ (1MTTF) 来度量,其中 MTTF 为平均无故障时间…