dubbo-远程服务暴露

DubboBootstrapApplicationListener

继承体系图

dubbo-远程服务暴露_第1张图片

源码解析

public class DubboBootstrapApplicationListener extends OneTimeExecutionApplicationContextEventListener
        implements Ordered {

    /**
     * The bean name of {@link DubboBootstrapApplicationListener}
     *
     * @since 2.7.6
     */
    public static final String BEAN_NAME = "dubboBootstrapApplicationListener";

    private final DubboBootstrap dubboBootstrap;

    public DubboBootstrapApplicationListener() {
        this.dubboBootstrap = DubboBootstrap.getInstance();
    }

    /**
     * 在Spring容器初始化完成后执行某个方法  防止onApplicationEvent方法被执行两次
     */
    @Override
    public void onApplicationContextEvent(ApplicationContextEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            onContextRefreshedEvent((ContextRefreshedEvent) event);
        } else if (event instanceof ContextClosedEvent) {
            onContextClosedEvent((ContextClosedEvent) event);
        }
    }

    /**
     * ContextRefreshedEvent 事件会在Spring容器初始化完成会触发该事件
     */
    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        dubboBootstrap.start();
    }

    /**
     * close是spring容器真正销毁了才会触发
     */
    private void onContextClosedEvent(ContextClosedEvent event) {
        dubboBootstrap.stop();
    }

    @Override
    public int getOrder() {
        return LOWEST_PRECEDENCE;
    }
}

DubboBootstrap#start() 

start()方法

/**
     * Start the bootstrap
     */
    public DubboBootstrap start() {
        // 只初始化一次
        if (started.compareAndSet(false, true)) {
            ready.set(false);
            initialize();
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " is starting...");
            }
            // 导入dubbo服务
            exportServices();

            // Not only provider register
            if (!isOnlyRegisterProvider() || hasExportedServices()) {
                // 2. export MetadataService
                exportMetadataService();
                //3. Register the local ServiceInstance if required
                registerServiceInstance();
            }

            referServices();
            if (asyncExportingFutures.size() > 0) {
                new Thread(() -> {
                    try {
                        this.awaitFinish();
                    } catch (Exception e) {
                        logger.warn(NAME + " exportAsync occurred an exception.");
                    }
                    ready.set(true);
                    if (logger.isInfoEnabled()) {
                        logger.info(NAME + " is ready.");
                    }
                }).start();
            } else {
                ready.set(true);
                if (logger.isInfoEnabled()) {
                    logger.info(NAME + " is ready.");
                }
            }
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " has started.");
            }
        }
        return this;
    }
  1. initialize方法

    在start方法中,也会调用initialize方法,之前提到过,服务端启动的时候,dubbo在start方法中调用initialize方法做初始化,而客户端启动的时候会跳过initialize方法。

  2. exportServices方法

    initialize方法之后调用exportServices方法,该方法用于暴露服务,服务端使用

    private void exportServices() {
            //创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
            configManager.getServices().forEach(sc -> {
                // TODO, compatible with ServiceConfig.export()
                ServiceConfig serviceConfig = (ServiceConfig) sc;
                serviceConfig.setBootstrap(this);
    
                if (exportAsync) {
                    异步暴露,使用线程池暴露服务
                    ExecutorService executor = executorRepository.getServiceExporterExecutor();
                    Future future = executor.submit(() -> {
                        //暴露服务
                        sc.export();
                        //;//记录所有暴露的服务
                        exportedServices.add(sc);
                    });
                    asyncExportingFutures.add(future);
                } else {
                    sc.export();
                    exportedServices.add(sc);
                }
            });
        }
    
    public synchronized void export() {
            if (this.shouldExport()) {
                if (this.bootstrap == null) {
                    this.bootstrap = DubboBootstrap.getInstance();
                    this.bootstrap.initialize();
                }
    
                this.checkAndUpdateSubConfigs();
                this.serviceMetadata.setVersion(this.getVersion());
                this.serviceMetadata.setGroup(this.getGroup());
                this.serviceMetadata.setDefaultGroup(this.getGroup());
                this.serviceMetadata.setServiceType(this.getInterfaceClass());
                this.serviceMetadata.setServiceInterfaceName(this.getInterface());
                this.serviceMetadata.setTarget(this.getRef());
                if (this.shouldDelay()) {
                    DELAY_EXPORT_EXECUTOR.schedule(this::doExport, (long)this.getDelay(), TimeUnit.MILLISECONDS);
                } else {
                    this.doExport();
                }
    
                this.exported();
            }
        }

  3. hasExportedServices方法

    hasExportedServices()检查是否配置元数据中心的url,如果配置了,返回true。

  4. exportMetadataService

    exportMetadataService方法用于暴露本地元数据服务

       private void exportMetadataService() {
            metadataServiceExporters
                    .stream()
                    .filter(this::supports)
                    .forEach(MetadataServiceExporter::export);
        }

  5. registerServiceInstance方法

    registerServiceInstance用于将dubbo实例注册到专用于服务发现的注册中心。

  6. referServices方法

    referServices方法用于处理ReferenceConfig对象,但是这里有个问题。

ServiceConfig

继承体系图

dubbo-远程服务暴露_第2张图片

doExportUrlsFor1Protocol()方法

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
        String name = protocolConfig.getName();
        if (StringUtils.isEmpty(name)) {
            name = "dubbo";
        }

        Map map = new HashMap();
        map.put("side", "provider");
        appendRuntimeParameters(map);
        AbstractConfig.appendParameters(map, this.getMetrics());
        AbstractConfig.appendParameters(map, this.getApplication());
        AbstractConfig.appendParameters(map, this.getModule());
        AbstractConfig.appendParameters(map, this.provider);
        AbstractConfig.appendParameters(map, protocolConfig);
        AbstractConfig.appendParameters(map, this);
        MetadataReportConfig metadataReportConfig = this.getMetadataReportConfig();
        if (metadataReportConfig != null && metadataReportConfig.isValid()) {
            map.putIfAbsent("metadata-type", "remote");
        }

        String scope;
        Iterator var10;
        if (CollectionUtils.isNotEmpty(this.getMethods())) {
            Iterator var6 = this.getMethods().iterator();

            label172:
            while(true) {
                MethodConfig method;
                List arguments;
                do {
                    if (!var6.hasNext()) {
                        break label172;
                    }

                    method = (MethodConfig)var6.next();
                    AbstractConfig.appendParameters(map, method, method.getName());
                    String retryKey = method.getName() + ".retry";
                    if (map.containsKey(retryKey)) {
                        scope = (String)map.remove(retryKey);
                        if ("false".equals(scope)) {
                            map.put(method.getName() + ".retries", "0");
                        }
                    }

                    arguments = method.getArguments();
                } while(!CollectionUtils.isNotEmpty(arguments));

                var10 = arguments.iterator();

                while(true) {
                    ArgumentConfig argument;
                    Method[] methods;
                    do {
                        while(true) {
                            if (!var10.hasNext()) {
                                continue label172;
                            }

                            argument = (ArgumentConfig)var10.next();
                            if (argument.getType() != null && argument.getType().length() > 0) {
                                methods = this.interfaceClass.getMethods();
                                break;
                            }

                            if (argument.getIndex() == -1) {
                                throw new IllegalArgumentException("Argument config must set index or type attribute.eg:  or ");
                            }

                            AbstractConfig.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                        }
                    } while(methods.length <= 0);

                    for(int i = 0; i < methods.length; ++i) {
                        String methodName = methods[i].getName();
                        if (methodName.equals(method.getName())) {
                            Class[] argtypes = methods[i].getParameterTypes();
                            if (argument.getIndex() != -1) {
                                if (!argtypes[argument.getIndex()].getName().equals(argument.getType())) {
                                    throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                }

                                AbstractConfig.appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                            } else {
                                for(int j = 0; j < argtypes.length; ++j) {
                                    Class argclazz = argtypes[j];
                                    if (argclazz.getName().equals(argument.getType())) {
                                        AbstractConfig.appendParameters(map, argument, method.getName() + "." + j);
                                        if (argument.getIndex() != -1 && argument.getIndex() != j) {
                                            throw new IllegalArgumentException("Argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        String host;
        if (ProtocolUtils.isGeneric(this.generic)) {
            map.put("generic", this.generic);
            map.put("methods", "*");
        } else {
            host = Version.getVersion(this.interfaceClass, this.version);
            if (host != null && host.length() > 0) {
                map.put("revision", host);
            }

            String[] methods = Wrapper.getWrapper(this.interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("No method found in service interface " + this.interfaceClass.getName());
                map.put("methods", "*");
            } else {
                map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
            }
        }

        if (ConfigUtils.isEmpty(this.token) && this.provider != null) {
            this.token = this.provider.getToken();
        }

        if (!ConfigUtils.isEmpty(this.token)) {
            if (ConfigUtils.isDefault(this.token)) {
                map.put("token", UUID.randomUUID().toString());
            } else {
                map.put("token", this.token);
            }
        }

        this.serviceMetadata.getAttachments().putAll(map);
        host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = this.findConfigedPorts(protocolConfig, name, map);
        URL url = new URL(name, host, port, (String)this.getContextPath(protocolConfig).map((p) -> {
            return p + "/" + this.path;
        }).orElse(this.path), map);
        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
            url = ((ConfiguratorFactory)ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol())).getConfigurator(url).configure(url);
        }

        scope = url.getParameter("scope");
        if (!"none".equalsIgnoreCase(scope)) {
            if (!"remote".equalsIgnoreCase(scope)) {
                this.exportLocal(url);
            }

            if (!"local".equalsIgnoreCase(scope)) {
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                    var10 = registryURLs.iterator();

                    while(var10.hasNext()) {
                        URL registryURL = (URL)var10.next();
                        if (!"injvm".equalsIgnoreCase(url.getProtocol())) {
                            url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                            URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
                            if (monitorUrl != null) {
                                url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
                            }

                            if (logger.isInfoEnabled()) {
                                if (url.getParameter("register", true)) {
                                    logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                                } else {
                                    logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
                                }
                            }

                            String proxy = url.getParameter("proxy");
                            if (StringUtils.isNotEmpty(proxy)) {
                                registryURL = registryURL.addParameter("proxy", proxy);
                            }

                            Invoker invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
                            DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                            Exporter exporter = PROTOCOL.export(wrapperInvoker);
                            this.exporters.add(exporter);
                        }
                    }
                } else {
                    if (logger.isInfoEnabled()) {
                        logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
                    }

                    Invoker invoker = PROXY_FACTORY.getInvoker(this.ref, this.interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                    Exporter exporter = PROTOCOL.export(wrapperInvoker);
                    this.exporters.add(exporter);
                }

                WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter("metadata-type", "local"));
                if (metadataService != null) {
                    metadataService.publishServiceDefinition(url);
                }
            }
        }

        this.urls.add(url);
    }

URL地址 

dubbo://10.0.73.222:20880/com.jd.dubbo.EchoService?anyhost=true&application=echo-provider&bind.ip=10.0.73.222&bind.port=20880&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.jd.dubbo.EchoService&metadata-type=remote&methods=echo,hello&pid=74193&release=2.7.8&side=provider&timeout=1000×tamp=1628125664210 

你可能感兴趣的:(分布式)