Spring源码深度解析(郝佳)-学习-replace-method源码解析

tech2026-04-22  0

我们先来java类

TestChangeMethod.java

public class TestChangeMethod { public void changeMe() { System.out.println("change me"); } }

TestMethodReplacer.java

public class TestMethodReplacer implements MethodReplacer { @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { System.out.println("我替换了原有的方法"); return null; } }

Test.java

public static void main(String[] args) { ApplicationContext bf = new ClassPathXmlApplicationContext("classpath:spring_1_100/config_41_50/spring42.xml"); TestChangeMethod testChangeMethod =(TestChangeMethod) bf.getBean("testChangeMethod"); testChangeMethod.changeMe(); } }

xml实现

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="testChangeMethod" class="com.spring_1_100.test_41_50.test42.TestChangeMethod"> <replaced-method name="changeMe" replacer="replacer"> </bean> <bean id="replacer" class="com.spring_1_100.test_41_50.test42.TestMethodReplacer"> </beans>

【结果输出】 我替换了原有的方法

在这一篇博客中【https://blog.csdn.net/quyixiao/article/details/108368581】,我们分析了lookup-method标签的源码实现,而replaced-method的实现,大同小异,这里我们挑选一些关键部分源码分析一下 首先是代码解析部分:

/* 我们可以看到,无论是look-up还是replace-method都是构造了一个MethodOverride,并最终记录在了AbstractBeanDefinition中的methodOverrides属性中 * ,而这个属性如何使用以完成它所提供的功能呢,这个要在后续的章节中进行详细的介绍 */ public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); // 仅当在Spring默认的bean的子元素下且为 replace-method时有效 if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle = (Element) node; // 提取要替换的旧的方法 String name = replacedMethodEle.getAttribute("name"); // 提取对应的新的替换方法 String callback = replacedMethodEle.getAttribute("replacer"); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); // Look for arg-type match elements. List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type"); for (Element argTypeEle : argTypeEles) { // 记录参数 String match = argTypeEle.getAttribute("match"); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } }

在这个ReplaceOverride类的实例化过程中,将xml解析出来的name存储到methodName属性中,将xml中的replacer存储到了methodReplacerBeanName属性中。这个属性后面在cglib代理的时候会用到。

BeanDefinitionParserDelegate.java

在replaced-method分析中,对于TestChangeMethod这个实例的创建过程,同样的是使用了cglib代理, 从图中我们看到,对于changeMe()方法,最后accept()方法返回的是2,2对应的是

private static final Class<?>[] CALLBACK_TYPES = new Class<?>[] {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};

ReplaceOverrideMethodInterceptor这个拦截器类,因此,根据cglib 特性 ,在调用TestChangeMethod 的 changeMe() 方法时,会被ReplaceOverrideMethodInterceptor的intercept方法拦截到,因此我们来看看ReplaceOverrideMethodInterceptor类

ReplaceOverrideMethodInterceptor.java

/** * CGLIB MethodInterceptor to override methods, replacing them with a call * to a generic MethodReplacer. */ private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport mplements MethodInterceptor { private final BeanFactory owner; public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) { super(beanDefinition); this.owner = owner; } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable { ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method); // TODO could cache if a singleton for minor performance optimization //通过xml中的replacer配置的值找到实现MethodReplacer接口的bean MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class); //调用该bean的reimplement方法 return mr.reimplement(obj, method, args); } }

通过上面的cglib拦截,就调用到了我们实现了MethodReplacer接口的reimplement方法了。

@Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { System.out.println("我替换了原有的方法"); return null; }

本文github地址是 https://github.com/quyixiao/spring_tiny/blob/master/src/main/java/com/spring_1_100/test_41_50/test42

最新回复(0)