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 你可以通过 在获取前面 加上 &