关于mybatis spring与dubbo是怎么通过一个接口 你就能调用到一个bean方法的讲解

Mybatis 或者 dubbo 或者 feign 这些 东西 都是 你定义一个接口 然后就能 使用一个具体的bean(对象) 那么 你完全没有做任何事情(你的业务代码) 那是怎么去根据你定义的接口 你还能 依赖注入一个bean进去 还能调用的呢 面试的时候 一般 问 都是 一概而论的说一句 生成一个代理对象 那是怎么生成的呢 这一点 我今天记录一下

首先要弄清楚 spring的加载与生成bean的机制 spring在启动的时候 会 扫描 所有定义的 bean的类 并定义BeanDefinition 然后通过BeanDefinition 在调用creataBean方法的时候会 去实例 初始化 生成bean 在注入 那当我们定义一个接口 并生成代理对象 并通过spring去注入的时候 只要 自己定义好一个自定义的 BeanDefinition 并且类型定义为接口的类型 同时 生成bean的时候对应这个类型去定义一个 自己的 beanfactory 就可以 得到类似 mybatis 或者 dubbo 或者 feign 这种 代理的效果
下面是源码以及注解

package btree.MyBeanDefinitionRegistry;

import btree.FactoryBeanTest.MyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

/**
 * @author mz
 * @version V1.0
 * @Title MyBeanDefinitionRegistry
 * @Package btree.MyBeanDefinitionRegistry
 * @Description
 * @date 2020-03-12 15:49
 */
@Component
public class MyBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {


    /**
     * 将代理的 接口 自定义  bd 注册到spring
     * @param beanDefinitionRegistry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 这里 TestTrsultInterface 是我们定义的接口 需要被注入的接口应用类型
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TestTrsultInterface.class);
        //定义一个通用的 BeanDefinition
        GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
        //设置 BeanDefinition 的bean的构造方法的值
        definition.getConstructorArgumentValues().addGenericArgumentValue(TestTrsultInterface.class);
        //定义 beanfactory 要使用这个 factory 去生成你的bean
        definition.setBeanClass(MyFactoryBean.class);
        //bean的注入方式
        definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
        //将这个 BeanDefinition 注册要spring
        beanDefinitionRegistry.registerBeanDefinition(TestTrsultInterface.class.getSimpleName(), definition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

}

然后定义自己的 beanfactory

package btree.FactoryBeanTest;

import btree.proxy.MyProxy;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.Proxy;

/**
 * @author mz
 * @version V1.0
 * @Title MyFactoryBean
 * @Package btree.FactoryBeanTest
 * @Description
 * @date 2020-03-09 22:53
 */
public class MyFactoryBean<T> implements FactoryBean<T> {

    Class<T> myInterface;
    //这个地方 会 被 definition.getConstructorArgumentValues().addGenericArgumentValue(TestTrsultInterface.class); 设置值
    public MyFactoryBean(Class<T> myInterface) {
        this.myInterface = myInterface;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public T getObject() {
        MyProxy myProxy = new MyProxy();
        T o = (T) Proxy.newProxyInstance(myInterface.getClassLoader(), new Class[]{myInterface}, myProxy);
        return o;
    }

    @Override
    public Class<T> getObjectType() {
        return myInterface;
    }
}

定义一个自己的代理对象:

package btree.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author mz
 * @version V1.0
 * @Title MyProxy
 * @Package btree.proxy
 * @Description
 * @date 2020-03-12 15:42
 */
public class MyProxy<T>  implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.err.println("调用代理对象成功,调用方法:"+method.getName());
        return "success";
    }
}

定义你的接口(只有接口没有实现类 也没有配置 @Component 以及xml)

package btree.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author mz
 * @version V1.0
 * @Title MyProxy
 * @Package btree.proxy
 * @Description
 * @date 2020-03-12 15:42
 */
public class MyProxy<T>  implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.err.println("调用代理对象成功,调用方法:"+method.getName());
        return "success";
    }
}

最终调用效果:
在这里插入图片描述
可以看到 idea 有个警告 因为 idea 没有发现 有 定义的bean的地方 但是 我们 其实已经调用成功了
在这里插入图片描述
这里有几点要注意一下 当 spring 发现你定义的bean类型 是 实现了 FactoryBean 接口的时候 就会通过这个接口的 getObject方法 去生成你的bean 当然 你要想得到 你生成bean本身 就是 比如当前 你要 得到 你这个BeanDefinition 代码内定义的bean 就是 MyFactoryBean 你可以通过 在获取前面 加上 &

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值