前言
前面那篇文章我们从源码层面解析了Dubbo的服务暴露过程,今天我们继续源码解析,Dubbo服务引用/订阅流程。
环境配置
使用的Dubbo版本为3.2.0,注册中心使用zookeeper,demo为官方springboot演示代码。
Consume启动
可以看到,启动类上还是一个@EnableDubbo注解,和Provide启动并无差别,使用@DubboReference注解注入了DemoService,这个注解是不是很陌生,我们之前学习spring框架的时候只用过@Autowired、@Resource,@EnableDubbo在这里的作用和原理是什么呢?我们继续往下看
java
public class DubboSpringInitializer {
public static void initialize(BeanDefinitionRegistry registry) {
//.......省略非核心代码
// init dubbo context
initContext(context, registry, beanFactory);
}
private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory) {
// register common beans
DubboBeanUtils.registerCommonBeans(registry);
}
static void registerCommonBeans(BeanDefinitionRegistry registry) {
......
//这里主要是处理@DubboReference和@Reference注解
registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
ReferenceAnnotationBeanPostProcessor.class);
// register ApplicationListeners 注册监听器,这里很重要
registerInfrastructureBean(registry, DubboDeployApplicationListener.class.getName(), DubboDeployApplicationListener.class);
registerInfrastructureBean(registry, DubboConfigApplicationListener.class.getName(), DubboConfigApplicationListener.class);
// Dubbo config initializer 加载配置
registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);
......
}
还记得上篇文章registerCommonBeans()方法里注册了一个ReferenceAnnotationBeanPostProcessor处理器不,我们debug进去源码。
可以看到@DubboReference注解的职责就是将DemoService组装成BeanDefinition注册到了BeanDefinitionMap中,这个BeanDefinition的类型是ReferenceBean,这是个什么意思呢?我们找到这个接口。
java
public class ReferenceBean<T> implements FactoryBean<T>,
ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {
可以看到,它其实是一个FactoryBean,这里又牵扯到spring的知识了,我们找到ReferenceBean的getObject方法
java
@Override
public T getObject() {
//这里进行了重写
if (lazyProxy == null) {
createLazyProxy();
}
return (T) lazyProxy;
}
java
private void createLazyProxy() {
//set proxy interfaces
//see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
proxyFactory.addInterface(interfaceClass);
Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
for (Class<?> anInterface : internalInterfaces) {
proxyFactory.addInterface(anInterface);
}
if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
//add service interface
try {
Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
proxyFactory.addInterface(serviceInterface);
} catch (ClassNotFoundException e) {
// generic call maybe without service interface class locally
}
}
//动态代理
this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}
这里我们又见到了动态代理。
服务订阅
还记得在上篇文章中提到的DubboDeployApplicationListener监听器不,我们继续往下看
直接定位到init方法
java
protected synchronized void init() {
//创建代理
ref = createProxy(referenceParameters);
}
private void createInvoker() {
if (urls.size() == 1) {
URL curUrl = urls.get(0);
//这里
invoker = protocolSPI.refer(interfaceClass, curUrl);
// registry url, mesh-enable and unloadClusterRelated is true, not need Cluster.
if (!UrlUtils.isRegistry(curUrl) &&
!curUrl.getParameter(UNLOAD_CLUSTER_RELATED, false)) {
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(invoker);
invoker = Cluster.getCluster(getScopeModel(), Cluster.DEFAULT).join(new StaticDirectory(curUrl, invokers), true);
}
}
中间链路比较长,我们直接跳到这里
至此,我们已经初始化好了服务代理类,后续的方法调用,就是使用的这个代理类处理器。
总结
最后,还是用一段话总结一下,ReferenceAnnotationBeanPostProcessor处理器会将带有@DubboReference注解的属性扫描成ReferenceBean类型的BeanDefinition,ReferenceBean是一个工厂bean,它的getObject方法会创建代理类。DubboDeployApplicationListener监听器接收到spring刷新完成事件后会进行服务的订阅,与注册中心建立连接,将消费方的信息进行注册,订阅服务方的信息,并写入本地临时文件,最后会创建代理类 InvokerInvocationHandler,后续远程方法的调用都是这个Handler进行处理。