Dubbo源码(1)-服务注册

dubbo源码学习(1)- 服务注册

  1. SimpleApplicationEventMulticaster
    spring 事件广播器,触发监听器的事件
    listener.onApplicationEvent(event);
  2. DubboBootstrapApplicationListener extends OnceApplicationContextEventListener
    // 监听器进行启动 dubboBootstrap
    在这里插入图片描述
public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {
    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        dubboBootstrap.start();
    }
}
  1. DubboBootstrap启动过程进行暴露服务
    在这里插入图片描述
public class DubboBootstrap{
 public DubboBootstrap start() {
        if (started.compareAndSet(false, true)) {
            ready.set(false);
            initialize();
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " is starting...");
            }
            // 1. export Dubbo Services
            // 开始暴露服务
            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.");
                    }
                    ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
                    exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
                }).start();
            } else {
                ready.set(true);
                if (logger.isInfoEnabled()) {
                    logger.info(NAME + " is ready.");
                }
                ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
                exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
            }
            if (logger.isInfoEnabled()) {
                logger.info(NAME + " has started.");
            }
        }
        return this;
    }

    private void exportServices() {
     // configManger.getServices() 里面就是所有服务,遍历
        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(() -> {
                    try {
                        exportService(serviceConfig);
                    } catch (Throwable t) {
                        logger.error("export async catch error : " + t.getMessage(), t);
                    }
                });
                // 记录暴露服务
                asyncExportingFutures.add(future);
            } else {
                exportService(serviceConfig);
            }
        });
    }

    private void exportService(ServiceConfig sc) {
        if (exportedServices.containsKey(sc.getServiceName())) {
            throw new IllegalStateException("There are multiple ServiceBean instances with the same service name: [" +
                    sc.getServiceName() + "], instances: [" +
                    exportedServices.get(sc.getServiceName()).toString() + ", " +
                    sc.toString() + "]. Only one service can be exported for the same triple (group, interface, version), " +
                    "please modify the group or version if you really need to export multiple services of the same interface.");
        }
        // 调用服务
        sc.export();
        exportedServices.put(sc.getServiceName(), sc);
    }
}

configManager 存放的信息
在这里插入图片描述

  1. 暴露服务

4.1 服务暴露过程 由serviceConfig 交由 protocol执行后续流程
在这里插入图片描述
在这里插入图片描述

服务仓库类,存放services、consumers、providers

public class ServiceRepository extends LifecycleAdapter implements FrameworkExt {

    public static final String NAME = "repository";

    // services
    private ConcurrentMap<String, ServiceDescriptor> services = new ConcurrentHashMap<>();

    // consumers
    private ConcurrentMap<String, ConsumerModel> consumers = new ConcurrentHashMap<>();

    // providers
    private ConcurrentMap<String, ProviderModel> providers = new ConcurrentHashMap<>();

    // useful to find a provider model quickly with serviceInterfaceName:version
    private ConcurrentMap<String, ProviderModel> providersWithoutGroup = new ConcurrentHashMap<>();
}

类ServiceBean 继承了 ServiceConfig

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
        ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware {
    private static final long serialVersionUID = 213195494150089726L;

    private final transient Service service;

    private transient ApplicationContext applicationContext;

    private transient String beanName;

    // 用于触发事件
    private ApplicationEventPublisher applicationEventPublisher;
    
    /**
     * 暴露服务 
     * @since 2.6.5
     */
    @Override
    public void exported() {
        super.exported();
        // Publish ServiceBeanExportedEvent
        publishExportEvent();
    }

    /**
     * @since 2.6.5
     */
    private void publishExportEvent() {
        ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
        applicationEventPublisher.publishEvent(exportEvent);
    }
}

很多注册流程在ServiceConfig中


public class ServiceConfig<T> extends ServiceConfigBase<T> {
    @Override
    public synchronized void export() {
        if (bootstrap == null) {
            bootstrap = DubboBootstrap.getInstance();
            // compatible with api call.
            if (null != this.getRegistry()) {
                bootstrap.registries(this.getRegistries());
            }
            bootstrap.initialize();
        }

        checkAndUpdateSubConfigs();

        initServiceMetadata(provider);
        serviceMetadata.setServiceType(getInterfaceClass());
        serviceMetadata.setTarget(getRef());
        serviceMetadata.generateServiceKey();

        if (!shouldExport()) {
            return;
        }
        // 延迟暴露
        if (shouldDelay()) {
            DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
        } else {
            // 去暴露服务
            doExport();
        }
        //暴露之后的事情
        exported();
    }
    // 暴露服务
    protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("The service " + interfaceClass.getName() + " has already unexported!");
        }
        if (exported) {
            return;
        }
        //
        exported = true;

        if (StringUtils.isEmpty(path)) {
            path = interfaceName;
        }
        // 
        doExportUrls();
        // 
        bootstrap.setReady(true);
    }

    private void doExportUrls() {
        // 获得 服务仓库
        ServiceRepository repository = ApplicationModel.getServiceRepository();
        // 反射获得服务的接口类信息,并注册到服务仓库服务仓库的services中
        ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
        // 组合服务所有信息,添加到到服务仓库中provider中
        repository.registerProvider(
                getUniqueServiceName(),
                ref,
                serviceDescriptor,
                this,
                serviceMetadata
        );

        // 通过注册中心配置,得到注册中心的注册请求地址,支持多注册中心,转换为registry协议
        // nacos注册地址
        //registry://192.168.31.113:8848/org.apache.dubbo.registry.RegistryService?application=yifei-system-service&dubbo=2.0.2&id=org.apache.dubbo.config.RegistryConfig#0&namespace=lzzdubbo&pid=11036&qos.enable=false&registry=nacos&release=2.7.12&timestamp=1643380219846
        List<URL> registryURLs = ConfigValidationUtils.loadRegistries(this, true);

        int protocolConfigNum = protocols.size();
        for (ProtocolConfig protocolConfig : protocols) {
            String pathKey = URL.buildKey(getContextPath(protocolConfig)
                    .map(p -> p + "/" + path)
                    .orElse(path), group, version);
            // In case user specified path, register service one more time to map it to path.
            // 带上 group version 等信息注册进去
            repository.registerService(pathKey, interfaceClass);
            // 发布服务
            doExportUrlsFor1Protocol(protocolConfig, registryURLs, protocolConfigNum);
        }
    }

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs, int protocolConfigNum) {
        String name = protocolConfig.getName();
        if (StringUtils.isEmpty(name)) {
            name = DUBBO;
        }
        //组织一些服务接口的元数据信息
        Map<String, String> map = new HashMap<String, String>();
        // ....中间很多对map进行属性填充
        //init serviceMetadata attachments
        serviceMetadata.getAttachments().putAll(map);

        // export service 服务地址、端口,组装调用的url
        String host = findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = findConfigedPorts(protocolConfig, name, map, protocolConfigNum);
        // dubbo://192.168.31.15:21881/com.example.dubbo.UserDubboService?
        // anyhost=true&application=yifei-system-service&bind.ip=192.168.31.15&bind.port=21881&deprecated=false
        // &dubbo=2.0.2&dubbo.tag=tag1&dynamic=true&generic=false&
        // interface=com.example.dubbo.UserDubboService&metadata-type=remote&
        // methods=getUserName&pid=11036&qos.enable=false&release=2.7.12
        // &revision=1.0.0&service.name=ServiceBean:/com.example.dubbo.UserDubboService:1.0.0
        // &side=provider&timestamp=1643380626633&version=1.0.0
        URL url = new URL(name, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), map);

        // You can customize Configurator to append extra parameters
        // 是否有扩展点
        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }
        // 设置为null了    
        String scope = url.getParameter(SCOPE_KEY);
        // don't export when none is configured
        if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
                
            // export to local if the config is not remote (export to remote only when config is remote)
            // 只限本地 调用的 
            //injvm://127.0.0.1/com.example.dubbo.UserDubboService?anyhost=true&application=yifei-system-service&bind.ip=192.168.31.15&bind.port=21881&deprecated=false&dubbo=2.0.2&dubbo.tag=tag1&dynamic=true&generic=false&interface=com.example.dubbo.UserDubboService&metadata-type=remote&methods=getUserName&pid=11036&qos.enable=false&release=2.7.12&revision=1.0.0&service.name=ServiceBean:/com.example.dubbo.UserDubboService:1.0.0&side=provider&timestamp=1643380626633&version=1.0.0
            if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            // export to remote if the config is not local (export to local only when config is local)
            // 只限远程调用的
            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                    for (URL registryURL : registryURLs) {
                        if (SERVICE_REGISTRY_PROTOCOL.equals(registryURL.getProtocol())) {
                            url = url.addParameterIfAbsent(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE);
                        }

                        //if protocol is only injvm ,not register
                        if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
                            continue;
                        }
                        url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
                        // 生成监控地址
                        URL monitorUrl = ConfigValidationUtils.loadMonitor(this, registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            if (url.getParameter(REGISTER_KEY, true)) {
                                logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " +
                                        registryURL);
                            } else {
                                logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                            }
                        }

                        // For providers, this is used to enable custom proxy to generate invoker
                        String proxy = url.getParameter(PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
                            registryURL = registryURL.addParameter(PROXY_KEY, proxy);
                        }
                        // private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

                        // javasisitProxyFactory
                        Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
                                registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
                        // 构建注册代理
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        // 调用注册方法进行 服务注册 使用了责任链QosProtocolWrapper->ProtocolFilterWrapper ->ProtocolListenerWrapper->
                        //InterfaceCompatibleRegistryProtocol->
                        Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else {
                    if (logger.isInfoEnabled()) {
                        logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                    }
                    Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, url);
                    // 
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
                    exporters.add(exporter);
                }

                MetadataUtils.publishServiceDefinition(url);
            }
        }
        this.urls.add(url);
    }
}

4.2 核心注册代码
4.2.1 生成 服务实现类的代理类,用于被调用时的执行

// 生成interfaceClass代理类,proxy 的是对应的实现类
Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass,
registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
// 再包装一层 属性,包含代理类和元数据信息
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
// 使用protocol 进行暴露
Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);
exporters.add(exporter);
  • PROXY_FACTORY 代理工厂

将生成导出服务代理的实现,
JavassistProxy工厂是它的默认实现,
支持自适应扩展点


    /** 将生成导出服务代理的实现,
     * JavassistProxy工厂是它的默认实现
     * A {@link ProxyFactory} implementation that will generate a exported service proxy,the JavassistProxyFactory is its
     * default implementation
     */
    private static final ProxyFactory PROXY_FACTORY = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
  • JavassistProxyFactory 进行生成代理类
public class JavassistProxyFactory extends AbstractProxyFactory {
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> 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<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

代理类的属性包含
在这里插入图片描述

4.2.2 protocol进行执行注册流程

Exporter<?> exporter = PROTOCOL.export(wrapperInvoker);

PROTOCOL 如下, 也是自适应扩展点,默认是dubboProtocol

private static final Protocol PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

注册责任链
在这里插入图片描述

最后的InterfaceCompatibleRegistryProtocol 是继承于 RegistryProtocol,接着就调用 RegistryProtocol.export(final Invoker originInvoker)

注册协议类,进行向注册中心进行注册服务

public class RegistryProtocol implements Protocol {
    @Override
    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        URL registryUrl = getRegistryUrl(originInvoker);
        // url to export locally
        URL providerUrl = getProviderUrl(originInvoker);

        // Subscribe the override data
        // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call
        //  the same service. Because the subscribed is cached key with the name of the service, it causes the
        //  subscription information to cover.
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);

        providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
        // export invoker
        // 根据 provider 生成 dubbo调用器,
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);

        // url to registry
        final Registry registry = getRegistry(originInvoker);
        final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

        // decide if we need to delay publish
        boolean register = providerUrl.getParameter(REGISTER_KEY, true);
        if (register) {
            // todo 进行 注册,本例子 使用nacosRegistry 
            // registry 是一个 ListenerRegistryWrapper, 里面包了一个nacosRegistry ,调用register ,调用doRegister(是一个模板方法,
            // nacosRegistry 进行了实现,内部又使用nacos-client端进行了 注册过程)
            registry.register(registeredProviderUrl);
        }

        // register stated url on provider model
        registerStatedUrl(registryUrl, registeredProviderUrl, register);


        exporter.setRegisterUrl(registeredProviderUrl);
        exporter.setSubscribeUrl(overrideSubscribeUrl);

        // Deprecated! Subscribe to override rules in 2.6.x or before.
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

        notifyExport(exporter);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter<>(exporter);
    }
    @SuppressWarnings("unchecked")
    private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
        String key = getCacheKey(originInvoker);

        return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
            Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
            // 返回一个更新 用的代理
            return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
        });
    }
}

调用nacos-client中的注册服务namingService,进行服务注册


public class NacosRegistry extends FailbackRegistry {
    @Override
    public void doRegister(URL url) {
        final String serviceName = getServiceName(url);

        final Instance instance = createInstance(url);
        /**
         *  namingService.registerInstance with {@link org.apache.dubbo.registry.support.AbstractRegistry#registryUrl}
         *  default {@link DEFAULT_GROUP}
         *
         * in https://github.com/apache/dubbo/issues/5978
         */
        // 使用nacos-client 向nacos-server注册服务
        execute(namingService -> namingService.registerInstance(serviceName,
                getUrl().getParameter(GROUP_KEY, Constants.DEFAULT_GROUP), instance));
    }
}

在这里插入图片描述

其他注册器

扩展问题

  1. 如何设置异步暴露
    我这边是通过启动的时候提前获取DubboBootstrap实例,并设置好属性 ,这样监听器触发 时这个实例的exportAsync就是true

@SpringBootApplication
@EnableDubbo
public class Dubbo2ProviderApplication {

    public static void main(String[] args) {
        DubboBootstrap dubboBootstrap = DubboBootstrap.getInstance();
        dubboBootstrap.exportAsync();
        SpringApplication.run(Dubbo2ProviderApplication.class, args);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多多洛码代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值