dubbo框架揭秘之服务发布
通常情况下是通过Spring配置的方式去实现服务的发布,为了方便调试,我就不采用Spring配置的方式。
DemoService demo = new DemoServiceImpl();
ApplicationConfig config=new ApplicationConfig("hello-world-app"); RegistryConfig reg=new RegistryConfig("127.0.0.1:2181");
reg.setProtocol("zookeeper"); ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(20880); ServiceConfig<DemoService> service=new ServiceConfig<DemoService>();
service.setApplication(config);
service.setRegistry(reg);
service.setProtocol(protocol);
service.setInterface(DemoService.class);
service.setRef(demo);
service.setVersion("1.0");
service.export(); Thread.sleep(Integer.MAX_VALUE);
上面是服务发布的简短代码,其中最重要的就是export()方法。
public synchronized void export() {
           ...
            doExport()
    }
protected synchronized void doExport() {
       ...
        doExportUrls();
    }
private void doExportUrls() {
      //装配地址 registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=hello-world-app&dubbo=2.5.3&pid=5556®istry=zookeeper×tamp=1484484518418  
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        //配置为none不暴露
        if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
            //配置不是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() > 0
                        && 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);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    Exporter<?> exporter = protocol.export(invoker);
                    exporters.add(exporter);
                }
            }
        }
        this.urls.add(url);
    }
最终调用的是protocol.export(invoker)方法,protocol是通过扩展点机制动态生成的类:
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
        public void destroy() {
            throw new UnsupportedOperationException(
                    "method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
        }
        public int getDefaultPort() {
            throw new UnsupportedOperationException(
                    "method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
        }
     //调用该方法
        public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0)
                throws com.alibaba.dubbo.rpc.Invoker {
            if (arg0 == null)
                throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
            if (arg0.getUrl() == null)
                throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
            com.alibaba.dubbo.common.URL url = arg0.getUrl();
            String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
            if (extName == null)
                throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
                        + url.toString() + ") use keys([protocol])");
           //扩展点机制加载扩展类:
            com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader
                    .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
            return extension.export(arg0);
        }
        public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1)
                throws java.lang.Class {
            if (arg1 == null)
                throw new IllegalArgumentException("url == null");
            com.alibaba.dubbo.common.URL url = arg1;
            String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
            if (extName == null)
                throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
                        + url.toString() + ") use keys([protocol])");
            com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader
                    .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
            return extension.refer(arg0, arg1);
        }
    }
加载扩展类的核心方法:
public T getExtension(String name) {
        ...
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
private T createExtension(String name) {
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            injectExtension(instance);
            //cachedWrapperClasses在getAdaptiveExtension方法中被初始化,值为:ProtocolListenerWrapper、ProtocolFilterWrapper
            //这2个包装类通过装饰器模式,构造器实例化,最终返回ProtocolFilterWrapper(构造函数参数:ProtocolListenerWrapper(构造函数参数:RegistryProtocol))
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && wrapperClasses.size() > 0) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }    
所以,最终层层包装,调用RegistryProtocol的export(Invoker<T>)方法:
 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);
     //向注册中心注册地址:/dubbo/com.selrain.dubbodemo.DemoService/providers
        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);
                }
            }
        };
    }
参考:
dubbo框架揭秘之服务发布的更多相关文章
- dubbo框架揭秘之服务引用
		ApplicationConfig config = new ApplicationConfig("hello-worldp"); RegistryConfig reg = new ... 
- 基于Dubbo框架构建分布式服务(一)
		Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ... 
- 基于Dubbo框架构建分布式服务
		Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ... 
- [转载] 基于Dubbo框架构建分布式服务
		转载自http://shiyanjun.cn/archives/1075.html Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务 ... 
- (八)整合 Dubbo框架 ,实现RPC服务远程调用
		整合 Dubbo框架 ,实现RPC服务远程调用 1.Dubbo框架简介 1.1 框架依赖 1.2 核心角色说明 2.SpringBoot整合Dubbo 2.1 核心依赖 2.2 项目结构说明 2.3 ... 
- Dubbo源码学习--服务发布(DubboProtocol、Exporter)
		在Dubbo服务发布的整体流程一文中,只是分析了服务发布的整体流程,具体的细节还没有进一步分析.本节将继续分析服务暴露的过程.在ServiceConfig中通过一句话即可暴露服务,如下: Export ... 
- dubbo源码之服务发布与注册
		服务端发布流程: dubbo 是基于 spring 配置来实现服务的发布的,对于dubbo 配置文件中看到的<dubbo:service>等标签都是服务发布的重要配置 ,对于这些提供可配置 ... 
- 基于Dubbo框架构建分布式服务(集群容错&负载均衡)
		Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ... 
- Dubbo源码学习--服务发布(ServiceBean、ServiceConfig)
		前面讲过Dubbo SPI拓展机制,通过ExtensionLoader实现可插拔加载拓展,本节将接着分析Dubbo的服务发布过程. 以源码中dubbo-demo模块作为切入口一步步走进Dubbo源码. ... 
随机推荐
- mysql 创建数据 utf8
			CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 
- hdu_5213_Lucky(莫队算法+容斥定理)
			题目连接:hdu_5213_Lucky 题意:给你n个数,一个K,m个询问,每个询问有l1,r1,l2,r2两个区间,让你选取两个数x,y,x,y的位置为xi,yi,满足l1<=xi<=r ... 
- 彻底搞明白find命令的-mtime参数的含义【转载】
			转自: 彻底搞明白find命令的-mtime参数的含义-goolen-ITPUB博客http://blog.itpub.net/23249684/viewspace-1156932/ 以前一直没有弄明 ... 
- 转:移植SlidingMenu Android library,和安装example出现的问题解决
			很多项目都用到类似左侧滑动菜单的效果,比如facebook,evernote,VLC for android等等,这很酷 源代码可以从GitHub的https://github.com/jfeinst ... 
- jquery选中checkbox多选项并添加到文本框中
			<script> function check(){ var dd = ""; if($("input[type='checkbox'][name='moke ... 
- 关于Ubuntu下apt的一些用法及和yum的比较
			Fedora和Red Hat有yum安装软件,Ubuntu有apt工具. apt简单的来说,就是给Ubuntu安装软件的一种命令方式. 一.apt的相关文件 /etc/apt/sources.list ... 
- 你真的会使用XMLHttpRequest吗?
			看到标题时,有些同学可能会想:“我已经用xhr成功地发过很多个Ajax请求了,对它的基本操作已经算挺熟练了.” 我之前的想法和你们一样,直到最近我使用xhr时踩了不少坑儿,我才突然发现其实自己并不够了 ... 
- 用apache配置多个tomcat webapp
			The Apache HTTP Server Project is an effort to develop and maintain an open-source HTTP server for m ... 
- PHP 代码跟踪
			怎么知道代码的执行过程呢,也就是说怎么知道:是先执行哪些代码,然后执行哪些代码呢? 这里有一个非常犀利的函数,可以让你知道代码的执行过程 debug_backtrace() 函数. 来一段代码: L ... 
- [iOS]C语言技术视频-03-程序分支结构(switch)
			下载地址: 链接: http://pan.baidu.com/s/1iBpYA 密码: e2ym 
