新闻详情

新闻详情

首页 / 资讯中心 / 详情

深入剖析 Spring 源码中的 MethodOverride:lookup-method 与 replaced-method 的实现原理

发布时间:2026/9/13 15:18:24来源:尧图网络
深入剖析 Spring 源码中的 MethodOverride:lookup-method 与 replaced-method 的实现原理
深入剖析 Spring 源码中的 MethodOverridelookup-method 与 replaced-method 的实现原理【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址: https://gitcode.com/GitHub_Trending/so/source-code-hunter导读本文基于当前仓库对 Spring 框架源码的阅读笔记从org.springframework.beans.factory.support.MethodOverride类族入手完整剖析 Spring XML 配置中lookup-method与replaced-method两种方法覆盖机制的设计与实现。通过阅读本文你将理解方法覆盖相关的四个核心类MethodOverride、LookupOverride、ReplaceOverride、MethodOverrides的字段与匹配逻辑掌握两种标签的配置语法与适用场景并透过BeanDefinitionParserDelegate的标签解析与 CGLIB 子类实例化链路看清方法覆盖从 XML 解析到 Bean 实例化的完整底层原理。一、MethodOverride 概览方法覆盖的抽象基类org.springframework.beans.factory.support.MethodOverride是 Spring 方法覆盖机制的抽象基类它实现了BeanMetadataElement接口意味着每个方法覆盖对象都可以携带来源信息source用于错误定位与日志输出。MethodOverride定义了三个核心属性属性类型说明methodNameStringfinal被覆盖的方法名称overloadedboolean默认true方法是否允许重载默认开启即匹配时需考虑参数签名sourceObject可空配置来源例如 XML 元素节点public abstract class MethodOverride implements BeanMetadataElement { /** * 方法名称 */ private final String methodName; /** * 是否重载 */ private boolean overloaded true; /** * 源 */ Nullable private Object source; }基类还定义了一个抽象方法matches(Method method)交由子类实现。该方法用于判断给定的Method是否命中当前覆盖规则是后续MethodOverrides#getOverride进行方法匹配的核心入口public abstract boolean matches(Method method);MethodOverride的直接子类有两个分别对应 Spring XML 中两种可重写的机制详见 Spring-MethodOverride.mdlookup-method标签 —— 对应LookupOverride用于动态查找并返回容器中的其他 Beanlookup-method name bean/replaced-method标签 —— 对应ReplaceOverride用于在运行时替换目标方法的实现逻辑replaced-method name replacer/类图如下直观展示了两个子类与基类之间的继承关系二、LookupOverridelookup-method 标签对应的实体对象org.springframework.beans.factory.support.LookupOverride是lookup-method name... bean.../标签解析后生成的实体对象其核心用途是当目标方法被调用时不执行方法原有逻辑而是返回容器中指定的另一个 Bean 实例。2.1 属性列表LookupOverride只有两个属性Nullable private final String beanName; Nullable private Method method;属性说明beanName标签中bean属性指定的目标 Bean 名称method可空的Method对象若已通过反射解析出具体方法则直接以方法对象精确匹配2.2 matches 匹配逻辑matches方法优先判断已解析出的method对象是否存在存在则直接通过equals做全等比较否则退化为按方法名、重载开关、修饰符与参数数量进行匹配Override public boolean matches(Method method) { if (this.method ! null) { // 通过 equals 判断 return method.equals(this.method); } else { // 1. method 名称是否相同 // 2. 是否需要重载 // 3. 是不是 ABSTRACT 方法 // 4. 参数列表长度是否等于0 return (method.getName().equals(getMethodName()) (!isOverloaded() || Modifier.isAbstract(method.getModifiers()) || method.getParameterCount() 0)); } }从代码可以看出当overloaded false即不允许重载时只要方法名相同即匹配成功当允许重载时则要求目标方法为abstract方法或参数列表长度为 0否则视为不同的重载签名而不予匹配。这一设计使得lookup-method既能作用于抽象方法也能作用于无参方法同时避免误匹配同名重载方法。2.3 实际配置与使用案例lookup-method常用于原型prototypeBean 的依赖查找场景——例如单例 Bean 每次调用方法时都需要获取一个新的原型 Bean 实例。仓库笔记中给出了完整示例见 Spring-BeanDefinitionParserDelegate.mdbean idapple classorg.source.hot.spring.overview.ioc.bean.lookup.Apple meta keymeta-key valuemeta-value/ /bean bean idshop classorg.source.hot.spring.overview.ioc.bean.lookup.Shop lookup-method namegetFruits beanapple/ /beanpublic class LookupMain { public static void main(String[] args) { ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(META-INF/beans/spring-lookup-method.xml); Shop shop context.getBean(shop, Shop.class); System.out.println(shop.getFruits().getName()); } }上述代码中Shop#getFruits方法本身无需实现Spring 会在实例化shopBean 时生成其 CGLIB 子类并拦截getFruits调用直接返回容器中名为apple的 Bean 实例从而实现了方法级别的依赖注入。三、ReplaceOverridereplaced-method 标签对应的实体对象org.springframework.beans.factory.support.ReplaceOverride对应replaced-method name... replacer.../标签它允许开发者完全替换目标方法的实现逻辑由指定的MethodReplacer实现类接管方法调用。3.1 属性列表/** * 实现 MethodReplacer 接口的bean name * see MethodReplacer */ private final String methodReplacerBeanName; /** * 标签 arg-type 数据 */ private final ListString typeIdentifiers new LinkedList();属性说明methodReplacerBeanName实现org.springframework.beans.factory.support.MethodReplacer接口的 Bean 名称typeIdentifiersarg-type子标签的取值列表用于精确匹配被替换方法的参数类型构造方法只接收方法名与 replacer Bean 名其中methodName通过父类MethodOverride设置并对 replacer Bean 名做了非空校验public ReplaceOverride(String methodName, String methodReplacerBeanName) { super(methodName); Assert.notNull(methodName, Method replacer bean name must not be null); this.methodReplacerBeanName methodReplacerBeanName; }3.2 matches 匹配逻辑ReplaceOverride#matches的匹配过程比LookupOverride更严格分四步进行Override public boolean matches(Method method) { // 方法名称是否相同 if (!method.getName().equals(getMethodName())) { return false; } // 是否重载 if (!isOverloaded()) { // Not overloaded: dont worry about arg type matching... return true; } // If we get here, we need to insist on precise argument matching... // 类型标识数量是否和参数列表是否不相同 if (this.typeIdentifiers.size() ! method.getParameterCount()) { return false; } // 获取参数类型列表 Class?[] parameterTypes method.getParameterTypes(); for (int i 0; i this.typeIdentifiers.size(); i) { String identifier this.typeIdentifiers.get(i); // 判断 方法参数的类型是否在类型标识列表中 if (!parameterTypes[i].getName().contains(identifier)) { return false; } } return true; }匹配规则要点方法名必须与标签name属性一致若overloaded false不允许重载只按方法名匹配不再校验参数若允许重载则arg-type标识的数量必须与目标方法参数个数完全一致逐个比对参数类型的全限定名是否包含对应标识contains是包含判断因此arg-type可以写简化名如String可匹配java.lang.String。3.3 完整配置示例仓库笔记给出了replaced-method的完整 XML 配置与 replacer 实现见 Spring-MethodOverride.md?xml version1.0 encodingUTF-8? beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlnshttp://www.springframework.org/schema/beans xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd bean idapple classorg.source.hot.spring.overview.ioc.bean.lookup.Apple replaced-method replacermethodReplacerApple namehello arg-typeString/arg-type /replaced-method /bean bean idmethodReplacerApple classorg.source.hot.spring.overview.ioc.bean.lookup.MethodReplacerApple /bean /beansreplacer 必须实现MethodReplacer接口并重写reimplement方法public class MethodReplacerApple implements MethodReplacer { Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { System.out.println(方法替换); return obj; } }注意replacer属性指定的 Bean 必须是org.springframework.beans.factory.support.MethodReplacer接口的实现类这是方法替换生效的硬性前提。四、MethodOverrides方法覆盖的集合容器org.springframework.beans.factory.support.MethodOverrides是一个用于存储某个 Bean 全部方法覆盖规则的容器。在 Spring 中一个 Bean 可以同时配置多个lookup-method与replaced-method它们都会被收集到这个对象中并最终挂载到AbstractBeanDefinition上通过getMethodOverrides()访问。4.1 存储结构容器内部使用CopyOnWriteArraySet保证线程安全与元素去重private final SetMethodOverride overrides new CopyOnWriteArraySet();4.2 核心方法添加覆盖规则支持单个添加与批量合并两种方式。public void addOverride(MethodOverride override) { this.overrides.add(override); } public void addOverrides(Nullable MethodOverrides other) { if (other ! null) { this.overrides.addAll(other.overrides); } }获取命中的覆盖规则遍历全部候选覆盖规则调用各自的matches(Method)判断是否命中返回最后一个匹配项Nullable public MethodOverride getOverride(Method method) { MethodOverride match null; for (MethodOverride candidate : this.overrides) { if (candidate.matches(method)) { match candidate; } } return match; }MethodOverrides在 Bean 实例化阶段扮演关键角色SimpleInstantiationStrategy#instantiate正是通过beanDefinition.getMethodOverrides().isEmpty()来判断是否需要对目标 Bean 走 CGLIB 子类生成路径详见下文第五部分。五、从 XML 到实例方法覆盖的完整生命周期5.1 标签解析BeanDefinitionParserDelegate方法覆盖规则并非在实例化时才被感知而是在 XML 解析阶段就完成了收集。org.springframework.beans.factory.xml.BeanDefinitionParserDelegate在解析bean元素时会先后调用两个方法见 Spring-BeanDefinitionParserDelegate.md// lookup-override 标签解析 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // replaced-method sub-elements 标签解析 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());解析lookup-method读取name与bean属性构造LookupOverride并设置 source 后加入集合public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { // 获取子标签 NodeList nl beanEle.getChildNodes(); for (int i 0; i nl.getLength(); i) { Node node nl.item(i); // 是否有 lookup-method 属性 if (isCandidateElement(node) nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { Element ele (Element) node; // 获取 name 属性 String methodName ele.getAttribute(NAME_ATTRIBUTE); // 获取 bean 属性 String beanRef ele.getAttribute(BEAN_ELEMENT); // 创建 覆盖依赖 LookupOverride override new LookupOverride(methodName, beanRef); // 设置 source override.setSource(extractSource(ele)); overrides.addOverride(override); } } }解析replaced-method除name与replacer属性外还会遍历arg-type子标签读取match属性或元素文本作为类型标识public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl beanEle.getChildNodes(); for (int i 0; i nl.getLength(); i) { Node node nl.item(i); if (isCandidateElement(node) nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle (Element) node; // 获取 name 属性 String name replacedMethodEle.getAttribute(NAME_ATTRIBUTE); // 获取 replacer String callback replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); // 对象组装 ReplaceOverride replaceOverride new ReplaceOverride(name, callback); // 处理 arg-type 标签 ListElement argTypeEles DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); for (Element argTypeEle : argTypeEles) { // 获取 match 数据值 String match argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); // match 信息设置 match (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { // 添加类型标识 replaceOverride.addTypeIdentifier(match); } } // 设置 source replaceOverride.setSource(extractSource(replacedMethodEle)); // 重载列表添加 overrides.addOverride(replaceOverride); } } }相关标签常量在BeanDefinitionParserDelegate中统一定义包括LOOKUP_METHOD_ELEMENT lookup-method、REPLACED_METHOD_ELEMENT replaced-method、REPLACER_ATTRIBUTE replacer、ARG_TYPE_ELEMENT arg-type、ARG_TYPE_MATCH_ATTRIBUTE match等保证了解析过程与 schema 定义的严格对应。5.2 校验与准备prepareMethodOverrides在AbstractAutowireCapableBeanFactory#createBean中创建 Bean 实例之前会先校验并准备方法覆盖信息// 校验和准备 bean 中的方法覆盖 mbd.prepareMethodOverrides();这一步由AbstractBeanDefinition#prepareMethodOverrides完成对每个MethodOverride若其中overloaded开关为 true则尝试通过反射解析出具体的Method对象对于LookupOverride会填充其method字段为后续精确匹配做准备若目标方法不存在或解析失败则抛出BeanDefinitionValidationException由createBean包装为BeanDefinitionStoreException抛出见 4、依赖注入(DI).md.md#L236-L243)。5.3 实例化策略选择有方法覆盖必须走 CGLIB方法覆盖的本质是改变方法行为无法通过普通反射实例化实现因此 Spring 必须为目标 Bean 生成 CGLIB 子类。SimpleInstantiationStrategy#instantiate中依据methodOverrides是否为空做出分流见 4、依赖注入(DI).md.md#L475-L522)// 如果 配置的bean 中没有方法覆盖则使用 Java 的反射机制实例化对象否则使用 CGLIB if (beanDefinition.getMethodOverrides().isEmpty()) { // ... 反射获取默认构造方法并实例化 return BeanUtils.instantiateClass(constructorToUse); } else { // 使用 CGLIB 来实例化对象 return instantiateWithMethodInjection(beanDefinition, beanName, owner); }在子类CglibSubclassingInstantiationStrategy的私有内部类CglibSubclassCreator#instantiate中可以看到 CGLIB 的具体装配见 4、依赖注入(DI).md.md#L566-L580)Enhancer enhancer new Enhancer(); // 将 bean 本身作为其父类 enhancer.setSuperclass(this.beanDefinition.getBeanClass()); enhancer.setCallbackFilter(new CallbackFilterImpl()); enhancer.setCallbacks(new Callback[] { NoOp.INSTANCE, new LookupOverrideMethodInterceptor(), new ReplaceOverrideMethodInterceptor() }); // 使用 CGLIB 的 create() 方法生成实例对象 return (ctor null) ? enhancer.create() : enhancer.create(ctor.getParameterTypes(), args);这里的LookupOverrideMethodInterceptor与ReplaceOverrideMethodInterceptor正是方法覆盖的最终执行者LookupOverrideMethodInterceptor拦截命中LookupOverride的方法通过MethodOverrides#getOverride(method)获取覆盖规则再依据beanName从容器中查找并返回目标 Bean 实例ReplaceOverrideMethodInterceptor拦截命中ReplaceOverride的方法获取methodReplacerBeanName对应的MethodReplacerBean并调用其reimplement(obj, method, args)方法完成逻辑替换。至此MethodOverride的完整调用链为XML 标签 → BeanDefinitionParserDelegate 解析成 LookupOverride/ReplaceOverride → 存入 MethodOverrides挂载到 BeanDefinition→ prepareMethodOverrides 校验解析 → SimpleInstantiationStrategy 检测到覆盖规则 → CGLIB 生成子类并注册拦截器 → 方法调用被拦截并执行查找/替换逻辑。六、两种覆盖机制的对比与选型建议维度lookup-methodreplaced-method对应类LookupOverrideReplaceOverride标签格式lookup-method name bean/replaced-method name replacer/子标签无arg-type支持match属性或元素文本核心作用方法调用时返回容器中指定 Bean方法调用时由MethodReplacer接管执行典型场景单例 Bean 每次获取新的原型 Bean抽象方法的动态实现运行时热替换方法实现逻辑如 AOP 风格的拦截增强匹配依据方法名 是否重载 abstract/无参判断方法名 是否重载 参数类型标识精确匹配实例化要求必须 CGLIB 子类化必须 CGLIB 子类化选型建议若需求是「方法调用返回另一个 Bean」尤其是原型 Bean 的按需获取优先使用lookup-method它比注入ObjectFactory/ApplicationContext更简洁是 Spring 官方推荐的注入原型依赖方式若需求是「彻底改写方法逻辑」则应使用replaced-method并实现MethodReplacer接口两种机制都会强制触发 CGLIB 子类生成因此目标 Bean 类不应被final修饰被覆盖方法也不应为final或private否则无法被子类拦截。结语方法覆盖是 Spring IoC 容器中一个容易被忽略却非常精巧的机制。通过MethodOverride抽象基类统一建模、LookupOverride与ReplaceOverride差异化匹配、MethodOverrides集合管理配合BeanDefinitionParserDelegate的标签解析和 CglibSubclassingInstantiationStrategy 的拦截器装配Spring 实现了对普通 Java 方法行为的动态改写能力。本文涉及的源码笔记分散于 Spring-MethodOverride.md、Spring-BeanDefinitionParserDelegate.md 与 4、依赖注入(DI).md.md) 等文档中感兴趣的读者可以沿着这些线索继续深入追踪CglibSubclassingInstantiationStrategy的完整实现。【免费下载链接】source-code-hunter 从源码层面剖析挖掘互联网行业主流技术的底层实现原理为广大开发者 “提升技术深度” 提供便利。目前开放 Spring 全家桶Mybatis、Netty、Dubbo 框架及 Redis、Tomcat 中间件等项目地址: https://gitcode.com/GitHub_Trending/so/source-code-hunter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Unity接入MediaPipe姿态数据的轻量级实时方案 2026/9/13 15:51:28

Unity接入MediaPipe姿态数据的轻量级实时方案

简介:本资源是一套基于Python与MediaPipe在Unity引擎中实现人体姿态追踪的完整实践方案,面向Unity初学者、计算机视觉入门者及跨领域项目开发者,解决多平台姿态数据实时采集与Unity可视化集成的技术难点。资源包共7个文件,包含2个…

阅读更多 →
lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对 2026/9/13 15:51:28

lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对

lo 迭代器工具详解:使用 it.SeqToSeq2 为 Go 序列生成带索引的键值对 【免费下载链接】lo 💥 A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...) 项目地址: https://gitcode.com/GitHub_Trending/lo/lo Seq…

阅读更多 →
How to Deploy to Production 2026/9/13 15:51:28

How to Deploy to Production

How to Deploy to Production 【免费下载链接】skills Skills Catalog for Codex 项目地址: https://gitcode.com/GitHub_Trending/skills4/skills Overview Production deployment using GitHub Actions with zero-downtime rolling updates. Time Required: 15-20 mi…

阅读更多 →
KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践 2026/9/13 15:51:28

KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践

KernelSU 模块 WebUI 开发指南:从 webroot 目录到 JavaScript API 的完整实践 【免费下载链接】KernelSU A Kernel based root solution for Android 项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU 导读 KernelSU 的模块不仅能执行开机脚本、…

阅读更多 →
基于Function Call的智能图书查询Agent设计与实现 2026/9/13 15:51:28

基于Function Call的智能图书查询Agent设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
15分钟上手|免费开源 RAW 调色工具 darktable 完整教程 2026/9/13 15:48:28

15分钟上手|免费开源 RAW 调色工具 darktable 完整教程

15分钟上手|免费开源 RAW 调色工具 darktable 完整教程 【免费下载链接】darktable darktable is an open source photography workflow application and raw developer 项目地址: https://gitcode.com/GitHub_Trending/da/darktable RAW 照片想精细调色&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞