Dubbo原理<三> 服务暴露

文章目录


前言

服务暴露源码全流程分析

一、服务暴露流程简述:

1、生成接口实例代理Invoker调用对象(invoker代理ref的调用)
2、包装invoker对象,比如:exportListenr(暴露成功后回调监听者)、filter(进行方法调用的时候各种过滤器)
3、进行本地暴露(生成一个new InjvmExporter(invoker)对象)
4、远程暴露(生成一个new DubboExporter(invoker),并开启web服务,监听端口)
5、注册服务和订阅服务(把provider url注册到zk,同时监听zk状态重连重注册、同时订阅configurators,重置export)

二、暴露源码分析,从ServiceConfig的export开始

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、injvm暴露过程:

在这里插入图片描述

1、我们先看一下proxFactory自适应类的配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、在看javassistProxyFactory如何生成ref的代理类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、生成的wrapper类如下:

实现了父类Wrapper的所有方法;被包装的类的方法调用,由wrapper进行转发调用;没有什么其它逻辑;就是额外获取了被包装的类属性

public class com.alibaba.dubbo.common.bytecode.Wrapper0 implements com.alibaba.dubbo.common.bytecode.Wrapper{
    public static String[] pns;//被包装类字段名
    public static java.util.Map pts;//被包装类 <字段名,字段类型>
    public static String[] mns;//被包装类的  所有方法名集合
    public static String[] dmns;//被包装类的 直系方法名集合
	public static Class[] mts; //被包装类的   方法参数类型

    com.alibaba.dubbo.common.bytecode.Wrapper0(){}

    public Object invokeMethod(Object instance, String methodName, Class[] paramTypes, Object[] paramValues) throws java.lang.reflect.InvocationTargetException {
        kd.bos.service.DispatchService w;
        try {
            w = ((kd.bos.service.DispatchService) $1);
        } catch (Throwable e) {
            throw new IllegalArgumentException(e);
        }
        try {
            if ("invoke".equals($2) && $3.length == 4) {
                return ($w) w.invoke((java.lang.String) $4[0], (java.lang.String) $4[1], (java.lang.String) $4[2], (java.lang.Object[]) $4[3]);
            }
        } catch (Throwable e) {
            throw new java.lang.reflect.InvocationTargetException(e);
        }
        throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + $2 + "\" in class kd.bos.service.DispatchService.");
    }

   public String[] getPropertyNames() {
        return pns;
    }public boolean hasProperty(String n) {
        return pts.containsKey($1);
    }

    public Class getPropertyType(String n) {
        return (Class) pts.get($1);
    }

    public String[] getMethodNames() {
        return mns;
    }

    public String[] getDeclaredMethodNames() {
        return dmns;
    }

    public void setPropertyValue(Object o, String n, Object v) {
        kd.bos.service.DispatchService w;
        try {
            w = ((kd.bos.service.DispatchService) $1);
        } catch (Throwable e) {
            throw new IllegalArgumentException(e);
        }
        throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" filed or setter method in class kd.bos.service.DispatchService.");
    }

    public Object getPropertyValue(Object o, String n) {
        kd.bos.service.DispatchService w;
        try {
            w = ((kd.bos.service.DispatchService) $1);
        } catch (Throwable e) {
            throw new IllegalArgumentException(e);
        }
        throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + $2 + "\" filed or setter method in class kd.bos.service.DispatchService.");
    }
}

4、此时的invoker对象层次是AbstractProxyInvoker(wrapper(ref)),通过字节码生成的invoker对象,负责ref实例具体方法的调用

5、扩展,此时我们可以看看jdk是如果代理我们的ref实例的:

在这里插入图片描述

6、我们再看protocol.export(proxyFactory.getInvoker(this.ref, this.interfaceClass, local));此时protocol也是Protocol接口的自适应对象;

在这里插入图片描述

public class ProtocolListenerWrapper implements Protocol {
……
	public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    		return (Exporter)("registry".equals(invoker.getUrl().getProtocol()) ? this.protocol.export(invoker) : new ListenerExporterWrapper(this.protocol.export(invoker), 		Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class).getActivateExtension(invoker.getUrl(), "exporter.listener"))));
	}//通过dubbo spi获取ExporterListener接口的实现类;
//假设registry即注册中心的暴露则不包装直接调用实现类继续暴露;是rpc的暴露则包装到ListenerExporterWrapper,(作用暴露成功通知)
……
}


public class ProtocolFilterWrapper implements Protocol {
……
	public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    	return "registry".equals(invoker.getUrl().getProtocol()) ? this.protocol.export(invoker) : this.protocol.export(buildInvokerChain(invoker, "service.filter", "provider"));
	}
	//假设假设registry即注册中心的暴露则不包装直接调用实现类继续暴露;  是rpc的暴露则把invoker包装一层filters(作用服务调用先进行filter)
……
}

在这里插入图片描述
在这里插入图片描述

7、包装完毕后到injvmProtocol进行暴露

在这里插入图片描述

四、进行远程暴露:回到ServiceConfig的doExportUrlsFor1Protocol方法远程暴露逻辑

Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
	Exporter<?> exporter = protocol.export(invoker);

1、 此处代理ref的invoker对象和上述调用一致

不过protocol.export中invoker父类中的url是registryURL:registry://172.18.1.204:2182/com.alibaba.dubbo.registry.RegistryService?application=mservice-tlx&dubbo=2.8.4&export=dubbo……
所以export暴露的时候,经过wrapper类的判断"registry".equals(invoker.getUrl().getProtocol()) ? this.protocol.export(invoker) 会直接走到RegistryProtocol进行暴露
2、根据协议类型进行远程暴露在这里插入图片描述

2、根据协议类型进行远程暴露

在这里插入图片描述

3、同理rpc协议暴露,会经过exportListener和filter 包装;最后调用到rpc协议实现类去;默认是dubbo协议;所以此时到DubboProtocol进行export

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、我们先分析下requestHandler如何处理消息的

在这里插入图片描述
在这里插入图片描述

5、再看如何创建netty server的创建

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、此时经过doLoclExport方法在DubboProtocol中的export服务成功;得到了DubboExport(invoker)对象 并 开启web监听

final RegistryProtocol.ExporterChangeableWrapper<T> exporter = this.doLocalExport(originInvoker);
final Registry registry = this.getRegistry(originInvoker);
final URL registedProviderUrl = this.getRegistedProviderUrl(originInvoker);
registry.register(registedProviderUrl);
final URL overrideSubscribeUrl = this.getSubscribedOverrideUrl(registedProviderUrl);
final RegistryProtocol.OverrideListener overrideSubscribeListener = new RegistryProtocol.OverrideListener(overrideSubscribeUrl);
this.overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
return new Export(){……}

我们再回到RegistryProtocol的export的后续方法

1、得到注册对象的流程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看看ZookeeperRegistry的父类做了什么:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、得到注册对象后,registry.register(registedProviderUrl) 注册providerUrl

在这里插入图片描述
在这里插入图片描述

3、注册provider后,会注册configurator节点并订阅其孩子 registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

在这里插入图片描述
在这里插入图片描述

4、此时已经远程暴露成功得到exporter对象,也启动web监听;也注册provider了,也订阅了configurators; 我们再看看订阅configurators后,收到变化后,如何重置exporter的

在这里插入图片描述
在这里插入图片描述
可以看看isMatch如何判断被监听到的url是否匹配
在这里插入图片描述
在这里插入图片描述
在看看配置url如何合并原始provider的
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
现在配置url重写原始providerUrl得到了新的providerUrl;再看如何重置exporter的

在这里插入图片描述
configurator url: 示例:
override://10.20.153.10/com.foo.BarService?category=configurators&dynamic=false&disbaled=true
禁用此ip的barservice的提供者
override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null
服务降级

到此服务暴露大体流程;远程暴露、服务注册、订阅和通知动作,都已经讲完 ;

六、得到的exporter的封装整体情况如下:

在这里插入图片描述
时序图如下:
在这里插入图片描述


后言

暴露的结果就是,监听消费者调用,缓存Exporter对象,用来调用接口实现类;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值