注:分析的Dubbo版本是2.5.7。
图1 ReferenceConfig.get()的时序图
ReferenceConfig的时序图如图1所示,我们来看下ProxyFactory的实现类,如下图2所示。
图2 ProxyFactory的实现类
来看下JdkProxyFactory的getProxy(Invoker<T>)实现,如下所示。
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
Class<?>[] interfaces = null;
String config = invoker.getUrl().getParameter("interfaces");
if (config != null && config.length() > 0) {
String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
if (types != null && types.length > 0) {
interfaces = new Class<?>[types.length + 2];
interfaces[0] = invoker.getInterface();
interfaces[1] = EchoService.class;
for (int i = 0; i < types.length; i++) {
interfaces[i + 1] = ReflectUtils.forName(types[i]);
}
}
}
if (interfaces == null) {
interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class};
}
return getProxy(invoker, interfaces);
}
getProxy(Invoker<T>,Class<?>)返回一个JDK动态代理,如下所示。
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
interfaces,
new InvokerInvocationHandler(invoker));
}
往深处走,我们要做的就是去分析InvokerInocationHandler的实现。
接下来,我们来看下ReferenceConfig在哪被使用到。使用ReferenceConfig的有ReferenceBean和ReferenceAnnotationBeanPostProcessor,下面我们只分析ReferenceBean。我猜测ReferenceAnnotationBeanPostProcessor有可能是用于注解的方式,不过目前我没有去验证过,只是猜测而已,SpringAop就是通过BeanPostProcessor来实现的。
ReferenceBean继承了ReferenceConfig,实现了FactoryBean。如果熟悉Spring中FactoryBean的作用,读到此处,应该对ReferenceBean要干什么有点眉目了。
图3 ReferenceBean继承了ReferenceConfig
ReferenceBean的getObject方法,返回ReferenceCofig的get()结果,源码如下。
@Override
public Object getObject() throws Exception {
return get();
}
由此我可以猜测,Dubbo的consumer端,将要调用的provider提供的接口interface,通过FactoryBean转换为JDK动态代理,而后在JDK动态代理里面封装了实现细节。这种方式我在Mybatis-spring中见过。
由ReferenceBean看出,Dubbo的contributor们还是很熟悉Spring的。
在DubboNamespaceHandler中注册了ReferenceBean,如下图所示。不理解NamespaceHandler的同学可以先去了解下Spring的NamespaceHandler,DubboNamespaceHandler用于解析Dubbo自定义的Spring标签。
图4 DubboNamespaceHandler中用到了ReferenceBean
DubboNamespaceHandler的源码如下,parse(Element,ParserContext)返回的是个RootBeanDefinition ,这个beanDefinition的beanClass正是ReferenceBean。为什么需要个RootBeanDefinition,因为Spring中每个定义的bean都会扫描为一个BeanDefinition,不理解的同学可以先去看下Spring IOC的实现。
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
private static final Pattern GROUP_AND_VERION = Pattern.compile("^[\\-.0-9_a-zA-Z]+(\\:[\\-.0-9_a-zA-Z]+)?$");
private final Class<?> beanClass;
private final boolean required;
public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanClass, required);
}
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
......
return beanDefinition;
}
}
如下图5所示,Spring扫描到<dubbo:reference ...>的时候,就会调用DubboNamespaceHandler来解析。
图5 consumer(消费者)端定义的xml
(adsbygoogle = window.adsbygoogle || []).push({});