美文网首页
Spring扩展点-MethodOverride(运行时方法重写

Spring扩展点-MethodOverride(运行时方法重写

作者: Wannay | 来源:发表于2022-01-01 05:14 被阅读0次

    1. 了解什么是Spring当中的MethodOverride

    Spring框架当中,为我们提供了一个机制,称为MethodOverride,我们称之为运行时方法重写。

    1.1 XML版本的IOC容器中的相关实现

    其实运行时方法重写,在SpringXML版本当中就已经提供了实现,可以通过配置lookup-methodreplace-method这两个标签去进行的相关配置,就会使用到运行时方法重写这个玩意。

    image.png

    XML版IOC容器中,我们来看看它的XmlBeanDefinitionReader组件对于bean标签的解析过程中,其中就包含了对这两个标签的解析

    image.png

    这个类所在的类和方法是BeanDefinitionParserDelegate.parseBeanDefinitionElement

    我们来看关键的对ReplaceOverrideLookupOverride的处理工作

    image.png image.png

    我们可以看到,针对于replace-method标签,被解析成为一个ReplaceMethodOverride对象,加入到BeanDefinition当中,而对于lookup-method标签,则是被解析成为一个LookupMethodOvrride对象。

    我们来看MethodOverride和这些组件有什么关系?

    image.png

    我们可以看到,MethodOverride的两个实现就是LookupOverrideReplaceOverride

    MethodOverride对象被维护在哪里?实际上在BeanDefinition当中就有维护这样的一个列表,用来存放需要进行运行时方法重写的方法信息。

    image.png

    1.2 注解版IOC容器中的实现

    在注解版中,并未提供ReplaceMethodOverride的实现,但是对于LookupOverride,是有提供相关的实现的。

    在注解版的IOC容器中,提供了@Lookup这样一个注解,专门用来提供实现LookupMethodOverride,对应的就是XML版本当中对于lookup-method的实现。

    1.3 ReplaceMethodOverrideLookupOverride如何使用?

    LookupMethodOverride的功能,是提供让方法能够返回自定义的对象,而不是调用目标方法去return对象,也就是实现的是方法返回值的替换功能。

    比如,可以通过如下这样的注解版的配置方式去使用到LookupOverride

        @Lookup
        public User getUser() {
            return null;
        }
    

    在xml当中,对应的等价代码是

    image.png

    它实现的功能是:

    • 1.如果@Lookup注解配置了value属性,那么,将会从容器中按照beanName去获取Bean作为方法的返回值去进行返回;如果没配置value属性,那么将会按照方法的返回值作为beanType,从容器中去获取Bean
    • 2.lookup-method指定的方法本身可以是抽象方法(比如接口当中的方法),因为并不会执行到真实的方法的真正逻辑,而是走的代理逻辑去从容器中获取要返回的对象。
    • 3.因为lookup-method实际上就是调用getBean从容器中拿对象,因此它可以实现原型Bean的获取功能。

    ReplaceMethodOverride实现的功能是什么?它其实更有方法重写这句话的韵味,在运行时去替换目标方法的逻辑。

    我们首先编写一个自定义的Replacer,实现MethodReplacer接口,并实现它的reimplement方法,在这个方法当中执行的逻辑,实际上就你要替换的方法逻辑。

        public static class Replacer implements MethodReplacer {
            @Override
            public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
                return null;
            }
        }
    

    下面要做的,就是在XML当中去进行配置(注解版似乎并未提供ReplaceMethodOverride的相关实现)。

    image.png

    这样,在运行时,目标方法,就会被替换成为我们自定义的Replacer组件当中实现的方法。

    1.4 @Lookup注解的扫描

    既然注解版容器也有提供@Lookup的支持,那么必然会存在扫描这个注解的逻辑,那么这个注解究竟是在何处被扫描的呢?

    这个注解的扫描其实隐藏的比较深,在AutowiredAnnotationBeanPostProcessor这个组件的推断构造器的同时对@Lookup注解去进行处理。

    而这个组件本身的作用是什么?其实就是处理@Autowired/@Resource/@Inject这些注解的自动注入逻辑,另外一方面是使用一大段的逻辑去进行推断即将要进行创建Bean的构造器,最终根据候选构造器选出一个合适的构造器去创建目标对象。

    我们可以看到它是遍历beanClass以及它的所有父类当中的所有标注了@Lookup注解的方法,将其封装成为LookupOverride对象,加入到BeanDefinition当中。

    image.png

    2. Spring当中如何实现MethodOverride

    2.1 对MethodOverride的实现

    其实实现运行时方法重写很简单,就是创建代理嘛,代理的目的不就是运行时方法重写嘛,因此很显然是创建代理去实现的逻辑。我们从Spring源码当中找到如何创建代理的逻辑?

    doGetBean当中,有如下的代码

    image.png

    很显然,我们可以知道,创建Bean的真正逻辑,一定是在createBeanInstance这个方法当中的。

    image.png

    在这个方法当中,首先有两个逻辑的判断,就是使用Supplier去创建Bean(这个一般使用的少,但是其实有在使用,如果有了解过SpringCloud-OpenFeign组件的源码的朋友,相信会见过这个Supplier的使用),以及使用FactoryMethod(@Bean标注的方法,这个用的就比较多了)去创建逻辑。这部分我们都暂时不管,pass掉。

    image.png

    接下来,就是根据自动注入的类型(XML版本当中配置的自动注入的情况),以及推断出来的构造器的类型,选用instantiateBean或者是autowireConstructor这两个方法去创建对象。

    其实最终都会走到SimpleInstantiationStrategy中的下面这样的一个方法,这里才是最终的逻辑。

    image.png

    如果没有MethodOverride的情况,直接使用构造去创建对象就行了,如果有MethodOverride的情况,那么需要走到下面的逻辑,我们从注释当中已经看清楚了,使用CGLIB去生成目标子类。

    image.png

    我们来看真正进行实例化的逻辑,我们发现已经差不多到底了,已经到了设置Callbacks的层面了,设置了一个LookupOverrideMethodInterceptor和一个ReplaceOverrideMethodInterceptor这两个关键的回调。

    image.png

    为什么设置了多个回调呢?怎么确定运行时要使用哪个回调?其实这就涉及到CGLIB代理当中的CallbackFilter,当accept方法返回了Callbacks数组中的哪个位置的索引index,运行时将会采用的目标回调就是Callbacks[index]所在的Callback

    image.png

    2.2 ReplaceMethodOverrideLookupMethodOverride对应的回调

    对于LookupMethodOverride的实现,我们可以看到,就是如果配置了name,将会采用按名去进行注入,如果没配置name,那么将会按照方法的返回值作为type去进行注入,蛮简单的。

    image.png

    对于ReplaceMethodOverride的实现,其实相当简单,从容器中按照beabName去获取配置的Replacer对象,然后调用Replacer对象的reimplement方法就行。

    image.png

    我们可以总结一个点:运行时方法重写,其实就是使用JDK/CGLIB去创建代理,去拦截掉目标方法的逻辑,去指定要替换的逻辑,搞不定,用代理总没错,在Spring当中对于这句话的体现的淋漓尽致!

    个人博客:http://wanna1314y.top:8090/

    相关文章

      网友评论

          本文标题:Spring扩展点-MethodOverride(运行时方法重写

          本文链接:https://www.haomeiwen.com/subject/xqhoqrtx.html