dubbo组成原理-service服务暴露

来源:互联网 发布:csgo 优化 编辑:程序博客网 时间:2024/05/18 18:22

继续上一篇dubbo的schema的定义,从DubboNamespaceHandler说起


这里对几个主要标签做一下说明。具体的阿里有专门出手册,手册地址为http://dubbo.io/User+Guide-zh.htm

1、<dubbo:service /> 用于服务生产者暴露服务配置

2、<dubbo:reference /> 用于服务消费者引用服务配置

3、<dubbo:protocol /> 用于服务生产者协议配置

4、<dubbo:registry /> 用于注册中心配置

5、<dubbo:method />用于方法级配置


至此用户通过dubbo的标签能完整的背spring使用
鄙人曾经不止一次看到过一句话  软件=数据+算法
容器加载的时候,通过读取用户定义的dubbo.xml配置文件,生成带了各种参数的javabean对象,然后通过复杂的算法,达到dubbo框架RPC的目的。这个设计思路和spring中的beandefinition、springmvc中的HandlerMapping 有异曲同工之妙。


service的发布

因为调用过程比较复杂,这里引用了一位大神的解释,可以给大家直观的认识


ServiceBean处理继承dubbo自己的配置抽象类以外,还实现了一系列的spring接口用来参与到spring容器的启动以及bean的创建过程中去。由于spring的实例化ServiceBean是单例模式的,在Spring的容器ApplicationContext的启动过程refresh过程中最后第二步会预先初始化单例的bean, 在bean的初始化过程会设置beanName,   设置容器applicationContext, 回调   InitializingBean的afterPropertiesSet

最后一步finishRefresh会触发ContextRefreshedEvent事件, 而ServiceBean实现了ApplicationListener接口监听了此事件, 而在之前一步实例化的ServiceBean注册了这个事件,所以ServiceBean的onApplicationEvent(ApplicationEvent event)方法被触发, 在这个方法中触发了export方法来暴露服务。

 public void onApplicationEvent(ApplicationEvent event) {        if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {        if (isDelay() && ! isExported() && ! isUnexported()) {                if (logger.isInfoEnabled()) {                    logger.info("The service ready on spring started. service: " + getInterface());                }                export();            }        }    }
跟进export()来到ServiceConfig

    public synchronized void export() {        if (provider != null) {            if (export == null) {                export = provider.getExport();            }            if (delay == null) {                delay = provider.getDelay();            }        }        if (export != null && ! export.booleanValue()) {            return;        }        if (delay != null && delay > 0) {            Thread thread = new Thread(new Runnable() {                public void run() {                    try {                        Thread.sleep(delay);                    } catch (Throwable e) {                    }                    doExport();                }            });            thread.setDaemon(true);            thread.setName("DelayExportServiceThread");            thread.start();        } else {            doExport();        }    }

继续看doExport

protected synchronized void doExport() {        if (unexported) {            throw new IllegalStateException("Already unexported!");        }        if (exported) {            return;        }        exported = true;        if (interfaceName == null || interfaceName.length() == 0) {            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");        }        checkDefault();        if (provider != null) {            if (application == null) {                application = provider.getApplication();            }            if (module == null) {                module = provider.getModule();            }            if (registries == null) {                registries = provider.getRegistries();            }            if (monitor == null) {                monitor = provider.getMonitor();            }            if (protocols == null) {                protocols = provider.getProtocols();            }        }        if (module != null) {            if (registries == null) {                registries = module.getRegistries();            }            if (monitor == null) {                monitor = module.getMonitor();            }        }        if (application != null) {            if (registries == null) {                registries = application.getRegistries();            }            if (monitor == null) {                monitor = application.getMonitor();            }        }        if (ref instanceof GenericService) {            interfaceClass = GenericService.class;            generic = true;        } else {            try {                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()                        .getContextClassLoader());            } catch (ClassNotFoundException e) {                throw new IllegalStateException(e.getMessage(), e);            }            checkInterfaceAndMethods(interfaceClass, methods);            checkRef();            generic = false;        }        if(local !=null){            if(local=="true"){                local=interfaceName+"Local";            }            Class<?> localClass;            try {                localClass = ClassHelper.forNameWithThreadContextClassLoader(local);            } catch (ClassNotFoundException e) {                throw new IllegalStateException(e.getMessage(), e);            }            if(!interfaceClass.isAssignableFrom(localClass)){                throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName);            }        }        if(stub !=null){            if(stub=="true"){                stub=interfaceName+"Stub";            }            Class<?> stubClass;            try {                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);            } catch (ClassNotFoundException e) {                throw new IllegalStateException(e.getMessage(), e);            }            if(!interfaceClass.isAssignableFrom(stubClass)){                throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName);            }        }        checkApplication();        checkRegistry();        checkProtocol();        appendProperties(this);        checkStubAndMock(interfaceClass);        if (path == null || path.length() == 0) {            path = interfaceName;        }        doExportUrls();    }

来到doExportUrls 方法

  @SuppressWarnings({ "unchecked", "rawtypes" })    private void doExportUrls() {        List<URL> registryURLs = loadRegistries(true);
//因为dubbo支持多协议配置,遍历所有协议分别根据不同的协议把服务export到不同的注册中心上去        for (ProtocolConfig protocolConfig : protocols) {            doExportUrlsFor1Protocol(protocolConfig, registryURLs);        }    }

doExportUrlsFor1Protocol方法有点多,这里就不贴出来了


protocol实现有很多


最终由RegistryProtocol提供暴露服务 export

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {        //export invoker        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);        //registry provider        final Registry registry = getRegistry(originInvoker);        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);        registry.register(registedProviderUrl);        // 订阅override数据        // FIXME 提供者订阅时,会影响同一JVM即暴露服务,又引用同一服务的的场景,因为subscribed以服务名为缓存的key,导致订阅信息覆盖。        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl);        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);        //保证每次export都返回一个新的exporter实例        return new Exporter<T>() {            public Invoker<T> getInvoker() {                return exporter.getInvoker();            }            public void unexport() {            try {            exporter.unexport();            } catch (Throwable t) {                logger.warn(t.getMessage(), t);                }                try {                registry.unregister(registedProviderUrl);                } catch (Throwable t) {                logger.warn(t.getMessage(), t);                }                try {                overrideListeners.remove(overrideSubscribeUrl);                registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);                } catch (Throwable t) {                logger.warn(t.getMessage(), t);                }            }        };    }


ServiceConfig.doExportUrls()执行具体的export过程

1. loadRegistries(true)

checkRegistry如果xml中没有配置注册中,从dubbo.properties中读取配置,构建RegistryConfig对象并赋值

构建注册中心URL统一数据模式集合List<registryUrl>

2. 因为dubbo支持多协议配置,遍历所有协议分别根据不同的协议把服务export到不同的注册中心上去

a) 判断是否是泛型暴露

b) 根据协议构建暴露服务的统一数据模型URL

c) 配置的了monitor加载monitor,并给URL设置MONITOR_KEY

d) 给注册中regitryUrl设置EXPORT_KEY值为前面构建的暴露服务url

e) 根据服务具体实现,实现接口以及regitryUrl从代理工厂ProxyFactory获取代理Invoker(继承于AbstractProxyInvoker),它是对具体实现的一种代理

f) Protocol.export(invoker) 暴露服务invoker

Invoker包含上一步传入的RegistryUrl, registryUrl的protocol值为registry

ProtocolListenerWrapper和ProtocolFilterWrapper对于协议为REGISTRY_PROTOCOL直接跳过,最终由RegistryProtocol处理export的过程

 

RegistryProtocol暴露服务过程

这里传入的Invoker是由RegistryUrl从ProxyFactory得到的Invoker

1. 从Invoker获取providerUrl,在获取cacheKey, 根据cacheKey获取本地缓存的ExporterChangeableWrapper(exporter代理,建立返回的exporter与protocol export出的exporter的对应关系), 如果存在返回。

2. 如果不存在,根据传入的 Invoker获取providerUrl, 在构建InvokerDelegete(originInvoker, providerUrl)

3. Protocol.exprot(invokerDelegete) 根据providerUrl 的协议(一般是dubbo协议)通过Protocol的设配类暴露务,得到exporter

4. 利用providerUr导出的exporter和invoker构建对象ExporterChangeableWrapper缓存到本地

5. 由Invoker得到registryUrl。

 在根据registryUrl从RegistryFactory获取Registry, 获取RegistryUrl的注册中心协议,这里我们拿zooKeeper协议为例。由dubbo的扩展机制得到的是ZookeeperRegistryFactory,得到注册器为ZookeeperRegistry

6. 由Invoker获取ProviderUrl在去除不需要在注册中心看到的字段得到registryProviderUrl

7. 注册中心(ZookeeperRegistry)注册registryProviderUrl

Registry.register(registryProviderUrl)

8. 由registryProviderUrl获取overrideSubscribeUrl,在构建OverrideListener

9. registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener) 注册中心订阅这个url, 用来当数据变化通知重新暴露, 哪zookeeper为例,暴露服务会在zookeeper生成一个节点,当节点发生变化的时候会触发overrideSubscribeListener的notify方法重新暴露服务

10.      构建并返回一个新的exporter实例

 

DubboProtocol暴露服务的过程

1. 从invoker获取统一数据模型url

2. 由url构建serviceKey(一般由端口,接口名,版本,group分组)

如:com.alibaba.dubbo.demo.DemoService:20880 这个是由接口和端口组成的

3. 构建DubboExporter放入本地map做缓存

4. 根据url openserver。 查找本地缓存以key为url.getAddress如果没有ExchangeServer创建。设置heartbeat时间,设置编码解码协议

根据url和ExchangeHandler  绑定server并返回(具体如何绑定专题介绍)

5. 返回DubboExporter对象


以上是比较提纲类的说明,如果理解不是很透彻的,我推荐结合另一篇从代码维度的分析。有助于消化理解

http://blog.csdn.net/jycwl/article/details/51481914


1 0
原创粉丝点击