天天看点

dubbo服务暴露原理

dubbo的xsd文档在jar包中的META-INF/dubbo.xsd

对标签的处理类dubbo中的定义写在META-INF/spring.handlers

dubbo标签的解析主要用到了DubboNamespaceHandler 这个类

public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }
           

InitializingBean –> afterPropertiesSet

ApplicationListener –> onApplicationEvent

设置了延迟暴露,dubbo在Spring实例化bean(initializeBean)的时候会对实现了InitializingBean的类进行回调,回调方法是afterPropertySet()

没有设置延迟或者延迟为-1,dubbo会在Spring实例化完bean之后,在刷新容器最后一步发布ContextRefreshEvent事件的时候,通知实现了ApplicationListener的类进行回调onApplicationEvent

ServiceBean

public void afterPropertiesSet() throws Exception {
     if (! isDelay()) {
            export();
        }
           

ServiceConfig

public synchronized void export() {
     doExport();
           
private void doExportUrls() {
         //加载注册中心
        List<URL> registryURLs = loadRegistries(true);
        //将registries变量里面的每个地址,拼上application和registryconfig里面的参数,拼成一个registryUrl
        for (ProtocolConfig protocolConfig : protocols) {
        //遍历protocols变量,将protocols列表中的每个protocol根据url暴露出去
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }
           
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
     //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务)
      if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
    //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露远程服务)
     if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                if (registryURLs != null && registryURLs.size() > 
                        && url.getParameter("register", true)) {
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
                        //获得执行者,包括接口、实现类等
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));

                        Exporter<?> exporter = protocol.export(invoker);
                        exporters.add(exporter);
           
//proxyFactory是SPI指定的,META-INF/dubbo/internal,key value形式
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

//protocol 是SPI指定的,是DubboPortocol
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
           

RegistryProtocol

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //里面调用DubboProtocol,并建立netty客户端,监听20880端口
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
        //使用zk客户端(旧版本zkclient,新版本curator),注册provider
        final Registry registry = getRegistry(originInvoker);
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
        registry.register(registedProviderUrl);
           

DubboProtocol

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    openServer(url);
           
private void openServer(URL url) {
        // find server.
        String key = url.getAddress();
        //client 也可以暴露一个只有server可以调用的服务。
        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支持reset,配合override功能使用
                server.reset(url);
            }
        }
    }
           
private ExchangeServer createServer(URL url) {
        try {
            //使用netty
            server = Exchangers.bind(url, requestHandler);