spring6源码阅读(四):spring-core解析

切换上游分支

虽然spring7的新特性很令人好奇,但目前spring6还是挺新的,所以还是切换到6.2.x的分支进行阅读吧。

克隆你的Fork:
代码

    git clone https://github.com/你的用户名/仓库名.git
添加上游远程:
代码

    cd 仓库名
    git remote add upstream https://github.com/原作者用户名/仓库名.git
获取上游分支:
代码

    git fetch upstream
切换到目标分支并创建本地分支:
代码

    git checkout -b <你的分支名> upstream/<你想处理的原始分支名>
例如,要处理 develop 分支,可以输入:
代码

    git checkout -b my-develop upstream/develop

源码阅读: cglib包

package-info内容如下:
Spring 对 CGLIB 3.3 的重新打包(带有 Spring 特定的补丁,仅供内部使用)。
这种重新打包技术避免了与应用程序级别或第三方库和框架的依赖关系的任何潜在冲突。

源码结构

image

此外,spring-core中的cglib和asm都是对原仓库的打包+补丁,白话就是粘贴过来之后做了一些功能适配。对于补丁代码,spring使用如下的格式

			// SPRING PATCH BEGIN
			setContextClass(superclass);
			// SPRING PATCH END

拓展:
Spring Framework 本体默认优先使用 JDK 动态代理:只要目标 bean 暴露了接口,AOP 基础设施(ProxyFactory, @EnableAspectJAutoProxy, @Transactional 等)都会生成 JDK 代理。只有在 JDK 代理不可行或你显式指定 proxyTargetClass=true 时,Spring 才会退回/切换到 CGLIB 子类代理(例如目标类没有接口,或你强制按类代理)。Spring Boot 改写了这个默认值,才会一上来就选 CGLIB。

cglib的入口类org.springframework.cglib.proxy.Enhancer

构造器

	/**
创建一个新的 Enhancer.每个生成的对象都应使用一个新 Enhancer 对象,并且不应跨线程共享。要创建生成类的其他实例,请使用接口 Factory 。
请参阅:
Factory
	 */
	public Enhancer() {
		super(SOURCE);
	}

其中SOURCE是一个静态变量 private static final Source SOURCE = new Source(Enhancer.class.getName());,Source类是抽象类AbstractClassGenerator的一个成员内部类,他们的作用仅仅是标识name,也就是Enhancer.class.getName()

此外,构造器上的注释“要创建生成类的其他实例,请使用接口 Factory ”,嗯,请仔细的看“生成类的其他实例”,人话版本就是“被代理类会默认实现Factory接口,如果想要再获取一个新的被代理实例,请使用Factory的接口方法”

Factory

该接口的方法大致分为两类,一个是生成实例的newInstance,另一个是管理回调的Callbacks方法。前者见名知意,后者就有点眼熟了,他很像spring-aop策略,实际上也正是该模式的基地。

但至此就有些令人迷惑了,我们看到的Callbacks方法似乎就是用于管理被代理类实际方法和切面方法的调用顺序,那么他真的生成了字节码吗?

答:Factory类是一个接口,他是需要在执行过程中动态实现的编入新的字节码文件的,也是cglib所强调的“不依赖显式接口定义”的类代理

使用

在cglib的源码阅读中,我们大致清楚了生成器的祖先接口Enhancer和生成实例的默认实现接口Factory,此时的问题就是spring如何利用?

测试仓库:https://github.com/wenzhuo4657/springTest/tree/main/spring-core/spring-core-04

测试结果


Before method: setName
(挥手,笑)
After method: setName
Before method: hello
(挥手,笑)
你好张三
After method: hello
Before method: setName
(挥手,笑)
After method: setName
Before method: hello
(挥手,笑)
你好李四
After method: hello

以上测试证实了Factory是默认的隐藏实现父类。

posted @ 2025-09-18 15:59  wenzhuo4657  阅读(5)  评论(0)    收藏  举报