Dubbo ServiceBean详解

ServiceBean类图

类继承图

Dubbo ServiceBean详解_第1张图片

成员变量和方法

Dubbo ServiceBean详解_第2张图片

服务暴露

服务暴露流程图

Dubbo ServiceBean详解_第3张图片

我们看几个核心的节点

ServiceConfig#doExport

protected synchronized void doExport() 

该方法为同步方法,在初始化时同步阻塞。
方法开始时进行一些列的检查,包含对provider,module,application,ref。

       if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            checkInterfaceAndMethods(interfaceClass, methods);
            checkRef();
            generic = Boolean.FALSE.toString();
        }

ref为当前暴露对象的引用,首先检查当前对象是否为GenericService实例,否则会对对应的接口和方法进行检查。

ServiceConfig#doExportUrls

    private void doExportUrls() {
        List registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

Dubbo支持多注册协议导出服务,也允许我们向多个注册中心注册服务,在上面的方法会加载对应的注册中心,并在每个协议下导出服务。

ServiceConfig#doExportUrlsFor1Protocol

Dubbo导出服务默认为dubbo协议

 String name = protocolConfig.getName();
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }

然后获取一些列基本参数
Dubbo ServiceBean详解_第4张图片

如果我们没有配置scope为remote,那么dubbo总会执行一次injvm暴露

  // export to local if the config is not remote (export to remote only when config is remote)
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }

exportLocal

    private void exportLocal(URL url) {
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(LOCALHOST)
                    .setPort(0);
            ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
            Exporter exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }

执行InjvmProtocol#export方法,执行injvm暴露

多注册中心暴露

  if (registryURLs != null && registryURLs.size() > 0) {
                    for (URL registryURL : registryURLs) {

获取对应invoker方法,并执行export

 Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                        Exporter exporter = protocol.export(wrapperInvoker);

Invoker 创建过程

Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

   Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
   DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

Dubbo ServiceBean详解_第5张图片

如上看到,dubbo的集中代理生成方式,Dubbo 默认的 ProxyFactory 实现类是 JavassistProxyFactory。

public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    public  T getProxy(Invoker invoker, Class[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    public  Invoker getInvoker(T proxy, Class type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

}

核心在getInvoke时生成对应的getWrapper方法

    public static Wrapper getWrapper(Class c) {
        while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
            c = c.getSuperclass();

        if (c == Object.class)
            return OBJECT_WRAPPER;

        Wrapper ret = WRAPPER_MAP.get(c);
        if (ret == null) {
            ret = makeWrapper(c);
            WRAPPER_MAP.put(c, ret);
        }
        return ret;
    }

getWrapper调用makeWrapper生成对应的代理对象,代码较多,暂不展示

RegistryProtocol#export

该方法主要负责完成:

  1. 调用 doLocalExport 导出服务
  2. 获取注册中心 URL
  3. 根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry
  4. 取已注册的服务提供者 URL
  5. 获取 register 参数
  6. 向服务提供者与消费者注册表中注册服务提供者
  7. 根据 register 的值决定是否注册服务
  8. 向注册中心注册服务
  9. 获取订阅 URL
  10. 创建监听器
  11. 向注册中心进行订阅 override 数据
  12. 创建并返回 DestroyableExporter

真实export

在doLocalExport方法中,会调用具体的协议的暴露方法
RegistryProtocol#doLocalExport

  exporter = new ExporterChangeableWrapper((Exporter) protocol.export(invokerDelegete), originInvoker);

会根据对应的协议执行协议的export方法

DubboProtocol#export

    public  Exporter export(Invoker invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
        exporterMap.put(key, exporter);

        //export an stub service for dispatching event
        Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
        Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
        if (isStubSupportEvent && !isCallbackservice) {
            String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
            if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
                if (logger.isWarnEnabled()) {
                    logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                            "], has set stubproxy support event ,but no stub methods founded."));
                }
            } else {
                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
            }
        }

        openServer(url);
        optimizeSerialization(url);
        return exporter;
    }
  1. 获取注册的url
  2. 获取服务标识,理解成服务坐标也行。由服务组名,服务名,服务版本号以及端口组成 serviceKey
  3. 键值对放入缓存中
  4. 启动服务器
  5. 优化序列化

openServer

    private void openServer(URL url) {
        // find server.
        String key = url.getAddress();
        //client can export a service which's only for server to invoke
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
                serverMap.put(key, createServer(url));
            } else {
                // server supports reset, use together with override
                server.reset(url);
            }
        }
    }

最终创建NettyServer

你可能感兴趣的:(Dubbo)