dubbo源碼之啓動、導出服務 v1.0

一.參考

二.架構
(一)分層架構
參考官網架構圖 http://dubbo.apache.org/books/dubbo-dev-book/design.html
從消費端來說,從上到下依次是
1.Service層,用戶定義的業務接口
2.Config層,讀取用戶配置(比如超時時間,group等),主要是ServiceConfig,ReferenceConfig.
3.Proxy層,因爲用戶定義的都是接口,消費端需要具體類對象才能調用。統一實現JDK動態代理或者cglib,向下層做調用.主要是ServiceProxy,ProxyFactory等.
4.Registry層,實現註冊中心的對接,從註冊中心拉取服務端,消費端地址列表.主要類爲Registry,RegistryFactory,RegistryService等.
5.Cluster層,集羣層,主要處理比如路由黑白名單,負載均衡,集羣中機器掛掉,調用失敗的重試策略等.主要類爲Cluster,Directory,Router,LoadBalance.
6.Monitor層.統計監控層,主要接口是Statistics,MonitorFactory,MonitorService.
7.Protocol層,主要處理使用哪種協議,比如dubbo還是http等.主要接口是Invocation,Result,Protocol,消費端的Invoker,服務端的Exporter等.
8.Exchange層,封裝請求爲Request,Response格式.主要接口爲Exchanger,ExchangeChannel,ExchangeClient,ExchangeServer等.
9.Transport層,處理區分不同的網絡框架,比如Netty,mina,包含網絡請求,編解碼器等.主要接口是Message,Channel,Transporter,Client,Codec,Server
10.序列化層,序列化請求對象.主要接口爲Serialization,ObjectInput,ObjectOutput,ThreadPool
(二)動態擴展
採用Microkernel +Plugin模式,Microkernel只負責組裝Plugin,Dubbo自身的功能也是通過擴展點實現.在擴展類的jar包內,放置擴展點配置文件:META-INF/dubbo/接口全限定名,內容爲:配置名=擴展實現類全限定名,多個實現類用換行符分隔.具體的動態擴展源碼後面新開貼分析.


三.源碼分析
(一)spring啓動,解析dubbo的xml.


1.spring啓動時讀取dubbo的xml配置文件,和讀取普通的spring的xml配置文件是一樣的。進入DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(),這個方法之前的邏輯參考之前寫的<spring源碼分析之架構和Refresh>帖子.這個方法裏面循環遍歷xml裏面的所有標籤.因爲是自定義標籤,每個標籤都進入BeanDefinitionParserDelegate#parseCustomElement().這個方法先調用DefaultNamespaceHandlerResolver#resolve()查找這個xml的解析類爲DubboNamespaceHandler.進入DubboNamespaceHandler#init()註冊xml的每個標籤的解析類.代碼如下

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 AnnotationBeanDefinitionParser());
}

然後進入DubboBeanDefinitionParser#parse()解析xml中的xml標籤.這裏面會註冊ApplicationConfig,RegistryConfig,ProtocolConfig,ServiceBean(用來處理dubbo:service標籤)類等到DefaultListableBeanFactory#beanDefinitionMap().這裏需要注意下解析<dubbo:service interface="xxx.xxx" ref="xxxid"/>標籤的ServiceBean類.普通的<bean>標籤由spring來處理,和dubbo沒關係.ServiceBean會把xml中ref引用的bean name,從ApplicationContext中取出bean的定義.把ref引用bean的完整路徑設置爲ServiceBean的id和name,比如xxx.DemoService.這個ServiceBean作爲獨立的bean放到beanDefinitionMap中.


(二)服務端導出dubbo的service


1.在ServiceBean#setApplicationContext()裏面把Spring裏面的ApplicationContext設置到Dubbo的SpringExtensionFactory#contexts成員屬性裏面.然後調用AbstractApplicationContext#addApplicationListener把dubbo設置爲spring的觀察者.
2.真正從spring調用到dubbo導出服務的接口的是進入到ServiceBean#afterPropertiesSet回調裏面.這個是spring創建dubbo的接口的bean,比如DemoService.調用getBean()時,傳入的beanName是前面獲取的<dubbo:service>的ref引用的完整路徑.所有的ServiceBean填充完對象屬性,開始做這個ServiceBean的初始化操作,回調ServiceBean#afterPropertiesSet()方法.
3.在ServiceBean#afterPropertiesSet()裏面.把ApplicationConfig,RegistryConfig,ProtocolConfig設置到ServiceBean裏面.
4.回調到ApplicationContextAware#setApplicationContext()裏面.ServiceBean#onApplicationEvent().進入到ServiceConfig#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!");
    }
    /* 遍歷ProviderConfig類的setXXX方法,然後調用.比如setQosPort(),具體的參數值從配置文件中取出.*/
    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;
        if (StringUtils.isEmpty(generic)) {
            generic = Boolean.TRUE.toString();
        }
    } else {
        try {
        	//創建dubbo接口的Class對象
            interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                    .getContextClassLoader());
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        //基本的是不是接口的檢查
        checkInterfaceAndMethods(interfaceClass, methods);
        //是不是xml裏面ref引用的檢查
        checkRef();
        generic = Boolean.FALSE.toString();
    }
    if (local != null) {
        if ("true".equals(local)) {
            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 implementation class " + localClass.getName() + " not implement interface " + interfaceName);
        }
    }
    if (stub != null) {
        if ("true".equals(stub)) {
            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 implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
        }
    }
    /* 遍歷ApplicationConfig類的setXXX方法,然後調用.比如setQosPort(),具體的參數值從配置文件中取出.*/
    checkApplication();
    //檢查Resistry層配置
    checkRegistry();
    //檢查Protocol層配置
    checkProtocol();
    appendProperties(this);
    checkStubAndMock(interfaceClass);
    if (path == null || path.length() == 0) {
        path = interfaceName;
    }
    //導出服務,主要是向註冊中心,比如zk節點上註冊提供者dubbo接口的名稱,路徑,版本,ip等等.代碼在後面分析
    doExportUrls();
    ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
    ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}

5.針對每種協議,導出接口url
進入ServiceConfig#doExportUrls().

private void doExportUrls() {
	//加載xml中配置的註冊中心的配置,生成url,代碼在後面6分析
    List<URL> registryURLs = loadRegistries(true);
    for (ProtocolConfig protocolConfig : protocols) {
    	//每個協議都導出到每個註冊中心裏面,代碼後面7分析
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

6.創建註冊的url地址
進入AbstractInterfaceConfig#loadRegistries.

protected List<URL> loadRegistries(boolean provider) {
    checkRegistry();
    List<URL> registryList = new ArrayList<URL>();
    //遍歷所有的註冊中心配置
    if (registries != null && registries.size() > 0) {
        for (RegistryConfig config : registries) {
            String address = config.getAddress();
            if (address == null || address.length() == 0) {
                address = Constants.ANYHOST_VALUE;
            }
            String sysaddress = System.getProperty("dubbo.registry.address");
            if (sysaddress != null && sysaddress.length() > 0) {
                address = sysaddress;
            }
            if (address != null && address.length() > 0
                    && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                Map<String, String> map = new HashMap<String, String>();
                //添加ApplicationConfig,對應接口的哪個應用
                appendParameters(map, application);
                //添加RegistryConfig,註冊中心地址
                appendParameters(map, config);
                map.put("path", RegistryService.class.getName());
                map.put("dubbo", Version.getVersion());
                map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                if (ConfigUtils.getPid() > 0) {
                    map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                }
                if (!map.containsKey("protocol")) {
                	//擴展機制加載協議的實現類,沒有配置的話默認使用dubbo協議
                    if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                        map.put("protocol", "remote");
                    } else {
                        map.put("protocol", "dubbo");
                    }
                }
                //根據map轉成url格式
                List<URL> urls = UrlUtils.parseURLs(address, map);
                for (URL url : urls) {
                    url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                    //添加xml中的zookeeper地址
                    url = url.setProtocol(Constants.REGISTRY_PROTOCOL);

                    /*最後map轉成url的格式爲:
                    zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=1879&qos.port=22222&timestamp=1583997678318
                    */
                    if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                            || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                        registryList.add(url);
                    }
                }
            }
        }
    }
    return registryList;
}

7.每種協議的導出 
進入ServiceConfig#doExportUrlsFor1Protocol(),代碼如下:

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {

    /* 省略部分代碼,主要是讀取配置,生成 值爲{side=provider, application=demo-provider, methods=sayHello, qos.port=22222, dubbo=2.0.0, pid=1879, interface=com.alibaba.dubbo.demo.DemoService, generic=false, timestamp=1583998111644} 的map  */
    ...

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

        //調用Wrapper#makeWrapper()動態生成dubbo接口的Wrapper封裝類,在後面11處分析
        //method指向dubbo接口的所有方法.
        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
        ...
    }

    //獲取註冊中心的地址和端口號
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    /* 這裏會加載Protocol擴展的實現類,代碼在後面8分析*/
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

    if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
            .hasExtension(url.getProtocol())) {
        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    }

    String scope = url.getParameter(Constants.SCOPE_KEY);
    // don't export when none is configured
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

        // export to local if the config is not remote (export to remote only when config is remote)
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
        	//導出本地接口,同一個jvm進程,代碼分析在後面的8
            exportLocal(url);
        }
        // export to remote if the config is not local (export to local only when config is 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,這裏一般就是Zookeeper的url.因爲這裏都是一個ServiceBean進來的,只有一個接口.
                for (URL registryURL : registryURLs) {
                    url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                    //加載監控中心的URL.默認本機的2181端口.
                    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);
                    }
                    /* 創建遠程dubbo調用的Invoker對象,和本地Injvm的過程類似,只是URL換了,進入10處. 返回的invoker還是JavassistProxyFactory創建的Invoker對象. */
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    //封裝遠程dubbo調用的Invoker對象爲DelegateProviderMetaDataInvoker格式.代碼在後面15處.
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                    /*遠程dubbo調用的DelegateProviderMetaDataInvoker轉成Exporter導出,後面16處分析.
                    這裏的Protocol還是三個實現類{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper},但是第一個傳入的是RegistryProtocol.三個實現類逆序調用.所以最後進入的是RegistryProtocol#export()方法創建DestroyableExporter,後面16處分析.先進入ProtocolFilterWrapper.export()方法,後面13處分析.*/
                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            } else {
                Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                Exporter<?> exporter = protocol.export(wrapperInvoker);
                exporters.add(exporter);
            }
        }
    }
    this.urls.add(url);
}

8.查找協議導出端口時,加載協議擴展.協議擴展後面新開貼分析.代碼如下,這裏傳入的protocolConfig是xml裏面配置的<dubbo:protocol>內容,name是dubbo,map是前面讀取的xml配置.

private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
    Integer portToBind = null;

    // parse bind port from environment
    //讀取環境變量裏面配置的dubbo端口,不是xml配置的
    String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
    portToBind = parsePort(port);

    // if there's no bind port found from environment, keep looking up.
    if (portToBind == null) {
    	//這裏讀取到xml配置的端口
        portToBind = protocolConfig.getPort();
        if (provider != null && (portToBind == null || portToBind == 0)) {
            portToBind = provider.getPort();
        }
        /* 動態擴展加載Protocol的所有實現類,調用Protocol#getDefaultPort()方法。這裏有三個實現類{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper}.先加載到ProtocolFilterWrapper類.ProtocolFilterWrapper的構造方法參數是Protocol對象,Protocol成員指向上一個Protocol實現類DubboProtocol.這一步通過ExtensionLoader#createExtension()方法實現.然後QosProtocolWrapper的成員指向ProtocolFilterWrapper.ProtocolListenerWrapper的成員指向QosProtocolWrapper.實際這裏返回的是DubboProtocol的端口 這塊新開貼分析源碼  */
        final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
        if (portToBind == null || portToBind == 0) {
            portToBind = defaultPort;
        }
        if (portToBind == null || portToBind <= 0) {
            portToBind = getRandomPort(name);
            if (portToBind == null || portToBind < 0) {
                portToBind = getAvailablePort(defaultPort);
                putRandomPort(name, portToBind);
            }
            logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
        }
    }

    // save bind port, used as url's key later
    map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));

    // registry port, not used as bind port by default
    String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
    Integer portToRegistry = parsePort(portToRegistryStr);
    if (portToRegistry == null) {
        portToRegistry = portToBind;
    }

    return portToRegistry;
}

9.導出本地同一jvm進程的dubbo接口

private void exportLocal(URL url) {
    if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
    	/* 設置本地地址爲 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=1879&qos.port=22222&side=provider&timestamp=1583998111644 的格式 */
        URL local = URL.valueOf(url.toFullString())
                .setProtocol(Constants.LOCAL_PROTOCOL)
                .setHost(LOCALHOST)
                .setPort(0);

        /* 這裏兩步操作
        (1).proxyFactory.getInvoker()獲取Invoker對象.ProxyFactory是spi動態擴展,進入ExtensionLoader#getExtension()方法。實現類只有一個StubProxyFactoryWrapper.它的構造方法傳入的ProxyFactory是JavassistProxyFactory.所以先調用StubProxyFactoryWrapper#getInvoker()->JavassistProxyFactory#getInvoker()(代碼在後面10分析)創建Invoker代表dubbo接口調用的信息,
        (2).protocol.export()也是動態擴展.這裏還是三個實現類{QosProtocolWrapper,ProtocolListenerWrapper,ProtocolFilterWrapper}.InjvmProtocol在QosProtocolWrapper的構造方法裏面傳入.這裏是逆序調用,先調用ProtocolFilterWrapper#export(代碼在後面12分析)->ProtocolListenerWrapper#export()(在13分析)->QosProtocolWrapper#export()(啓動Qos的Server)->InjvmProtocol#export().InjvmProtocol真正把Invoker對象轉成Exporter對象導出,在14處分析。最終生成的是InjvmExporter被封裝後的ListenerExporterWrapper. */
        Exporter<?> exporter = protocol.export(
                proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
        exporters.add(exporter);
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    }
}

10.創建Invoker.Invoker是代理對象,代理dubbo接口.
(1).如果是本地jvm協議,進入JavassistProxyFactory#getInvoker().方法參數proxy是前面調用時的xml中配置的ref標籤值,實現類DemoServiceImpl. type是接口 com.alibaba.dubbo.demo.DemoService,url是前面創建的local的Url值 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2434&qos.port=22222&side=provider&timestamp=1584001039834.
(2).如果是遠程dubbo調用,使用zk註冊的,參數不一樣。proxy不變,還是xml中ref標籤引用的dubbo接口實現類,type不變,指向dubbo接口,url變成 registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222&registry=zookeeper&timestamp=1584018965180 .
代碼如下:


public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
    //這裏的Wrapper是核心.封裝了所有接口Class對象到實際對象的引用.成員在下面代碼.這裏的getWrapper()調到後面11處的動態創建Wrapper
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
    /* 創建匿名類對象,所有的調用都會轉到Wrapper#invokeMethod()方法中去調用.所有的對象,方法名,方法的參數類型,參數值都封裝在Warpper對象中。*/
    return new AbstractProxyInvoker<T>(proxy, type, url) {
        @Override
        protected Object doInvoke(T proxy, String methodName,
                                  Class<?>[] parameterTypes,
                                  Object[] arguments) throws Throwable {

            /* invokeMethod是在Wrapper類的makeWrapper()方法裏面動態生成的.Wrapper類的成員裏面有dubbo實現類,invokeMethod會調用到 真實實現類的方法裏面。這裏在模擬jdk的動態代理實現 */
            return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
        }
    };
}

這裏返回的Invoker是個匿名內部類AbstractProxyInvoker.調用方法只有上面的doInvoke(),供外面的類調用.對象成員如下:
 

public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
	//接口的實現類
    private final T proxy;
    //接口的Class對象
    private final Class<T> type;
    //接口對應的註冊中心url地址
    private final URL url;
    ...
}

Wrapper類的成員,核心方法是invokeMethod,它是在makeWrapper()方法裏面動態生成的.

public abstract class Wrapper {
	//Class對象到實際實現對象的映射
    private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
    private static final Wrapper OBJECT_WRAPPER = {...}
}

動態生成的Wrapper類反編譯如下:

11.動態拼字串創建dubbo接口的封裝類.模擬動態代理功能.
入參爲dubbo接口的Class對象

private static Wrapper makeWrapper(Class<?> c) {
    if (c.isPrimitive())
        throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

    String name = c.getName();
    //獲取ClassLoader
    ClassLoader cl = ClassHelper.getClassLoader(c);

    //拼接代理類的字符串代碼.
    StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
    StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
    StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

    c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");

    ...
    //類名爲wrapper + 自增序號,比如Wrapper0
    long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
    //創建ClassGenerator對象
    ClassGenerator cc = ClassGenerator.newInstance(cl);
    cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
    cc.setSuperClass(Wrapper.class);
	...

    try {
    	//創建封裝類的Class
        Class<?> wc = cc.toClass();
        // setup static field.
      	...
        //add by feivirus
        //我自己加的,把Class對象打到文件裏反編譯
        Wrapper result = (Wrapper) wc.newInstance();
        String objName = getObjectName(result.getClass().getName());
        generateProxyClassFile(objName, new Class<?>[]{result.getClass()});
        //add end
        return result;
    } catch (RuntimeException e) {
        ...
    }
}

12.建立Filter的過濾職責鏈,返回被內含Filter職責鏈的新的Invoker.這Invoker內部包含JavassistProxyFactory創建的Invoker.
進入ProtocolFilterWrapper#export()方法.代碼如下:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
	//如果是遠程registry協議,進入這個分支.直接調用ProtocolListenerWrapper.export()
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    //如果本地jvm,進入這裏(1)先創建一個Filter接口實現類的職責鏈,代碼在下面.(2)protocol指向ProtocolListenerWrapper,代碼13分析
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    /* 加載所有Filter接口的實現類,這裏有EchoFilter,ClassLoaderFilter,GenericFilter,ContextFilter,TraceFilter,TimeoutFilter, MonitorFilter,ExceptionFilter八個*/
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (filters.size() > 0) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {
            	...
            	//集中式職責鏈,依次調用
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                ...
            };
        }
    }
    return last;
}

13.創建Exporter的觀察者Listener.
進入ProtocolListenerWrapper#export().

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
	/* 如果是遠程registry協議,進入這個分支.直接調用QosProtocolWrapper.export().啓動QosServer.然後進入RegistryProtocol#export()後面16處分析. */
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    /* 本地jvm註冊,進入這裏.導出的Exporter的實現類爲ListenerExporterWrapper。代碼如下. 這裏的protocol是動態擴展時構造方法傳進來的,指向QosProtocolWrapper,所以調用QosProtocolWrapper#export()(本地jvm不啓動qos servier.))->QosProtocolWrapper的protocol成員指向InjvmProtocol,在14處分析*/
    return new ListenerExporterWrapper<T>(protocol.export(invoker),
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
public class ListenerExporterWrapper<T> implements Exporter<T> {
	//實際創建的Exporter引用, 指向InjvmExporter.
    private final Exporter<T> exporter;

    private final List<ExporterListener> listeners;
 }

14.真正實現Invoker到Exporter的轉換.這裏導出的Exporter在上面13處封裝成了ListenerExporterWrapper,最終導出就是ListenerExporterWrapper。
進入InjvmProtocol#export(),代碼如下:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
	/* 創建InjvmExporter返回. 這裏的invoker指向前面12處新創建的包含filter過濾鏈的Invoker.*/
    return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}

InjvmExporter繼承自AbstractExporter。代碼如下:

class InjvmExporter<T> extends AbstractExporter<T> {

    private final String key;
    //這裏的key是dubbo接口的全路徑名,比如xxx.xxx.DemoService. value是InjvmExporter對象的this自身.
    private final Map<String, Exporter<?>> exporterMap;
}
public abstract class AbstractExporter<T> implements Exporter<T> {
	/* 這裏的Invoker指向12處新創建的包含filter過濾鏈的Invoker.這個Invoker包含JavassistProxyFactory創建的Invoker2。 Invoker2內的proxy指向dubbo接口的實現類,比如DemoServiceImpl*/
    private final Invoker<T> invoker;

    private volatile boolean unexported = false;
}

15.遠程Dubbo調用invoker包裝類.

public class DelegateProviderMetaDataInvoker<T> implements Invoker {
	//這裏指向JavassistProxyFactory創建的Invoker對象.
    protected final Invoker<T> invoker;
	//指向dubbo中xml配置的解析<dubbo:service>標籤的ServiceBean對象本身.
    private ServiceConfig metadata;
}

16.遠程dubbo調用的DelegateProviderMetaDataInvoker轉成Exporter接口導出.
從上面13處QosProtocolWrapper.export()方法調用過來,進入RegistryProtocol#export().入參爲上面的DelegateProviderMetaDataInvoker.代碼如下:

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    //export invoker
    /*協議換成dubbo協議的url,即dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843&qos.port=22222&side=provider&timestamp=1584018965207 導出,進入DubboProtocol#export(),導出dubbo協議的invoker,啓動dubbo協議的本機的netty server等待連接.後面代碼17處分析*/
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

    /*這裏獲取的url格式爲zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222&timestamp=1584018965180 */
    URL registryUrl = getRegistryUrl(originInvoker);

    //registry provider
    //進入ZookeeperRegistryFactory#createRegistry()創建和註冊中心連接的zookeeper連接,代碼在後面的22處分析
    final Registry registry = getRegistry(originInvoker);
    final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

    //to judge to delay publish whether or not
    boolean register = registedProviderUrl.getParameter("register", true);

    ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);

    if (register) {
    	//調用FailbackRegistry#register()向zk發出請求,添加節點路徑,註冊服務提供者,在後面23處分析.
        register(registryUrl, registedProviderUrl);
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }

    // 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(registedProviderUrl);
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
    //Ensure that a new exporter instance is returned every time export
    return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}

17.導出dubbo協議的invoker.
進入DubboProtocol#export(),這裏傳入的invoker爲ProtocolFilterWrapper包裝過的invoker.代碼如下:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
	//取出dubbo協議的url,dubbo:xxx,前面16處有.
    URL url = invoker.getUrl();

    // export service.
    //創建key字串爲com.alibaba.dubbo.demo.DemoService:20880
    String key = serviceKey(url);
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);

    //export an stub service for dispatching event
    Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
        String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
            if (logger.isWarnEnabled()) {
                logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                        "], has set stubproxy support event ,but no stub methods founded."));
            }
        } else {
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }
    /* 啓動dubbo服務器.DubboProtocol有成員serverMap,key是192.168.0.131:20880格式的地址,value是DubboProtocol#createServer()方法創建的ExchangeServer對象,代碼在後面19處分析 */
    openServer(url);
    //返回DubboExporter
    return exporter;
}

18.DubboExporter類,繼承自AbstractExporter,代碼在前面14處,含有invoker成員.

public class DubboExporter<T> extends AbstractExporter<T> {
	//字串爲com.alibaba.dubbo.demo.DemoService:20880
    private final String key;
    //key是上面的key,value是DubboExporter對象本身.
    private final Map<String, Exporter<?>> exporterMap;
}

19.啓動dubbo的ExchangeServer。

private ExchangeServer createServer(URL url) {
    ...
    ExchangeServer server;
    try {
    	/* url 爲dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&channel.readonly.sent=true&codec=dubbo&dubbo=2.0.0&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843&qos.port=22222&side=provider&timestamp=1584018965207 格式.
    	綁定地址.
    	requestHandler是dubbo協議的請求處理類,是ExchangeHandlerAdapter類型的DubboProtocol匿名內部類的成員變量,代碼在後面你的20處.bind()方法進入後面的21處分析.*/
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
    str = url.getParameter(Constants.CLIENT_KEY);
    if (str != null && str.length() > 0) {
        Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
        if (!supportedTypes.contains(str)) {
            throw new RpcException("Unsupported client type: " + str);
        }
    }
    return server;
}

20.DubboProtocol的請求處理類

ExchangeHandlerAdapter類的reply回調方法,代碼如下:
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
    if (message instanceof Invocation) {
        Invocation inv = (Invocation) message;
        /* 根據接口的serviceKey從exporterMap成員中找到對應的DubboExporter對象直接調用.serviceKey是com.alibaba.dubbo.demo.DemoService:20880格式,包含了接口的類型.*/
        Invoker<?> invoker = getInvoker(channel, inv);
        // need to consider backward-compatibility if it's a callback
        ...
        RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
        //調用DubboExporter的invoke方法,執行dubbo接口的代理方法.
        return invoker.invoke(inv);
    }
    throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}

21.綁定ExchangeServer
進入exchange.Exchangers#bind().傳入的url爲上面19處的url.代碼如下:

public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    ...
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    /*這裏的getExchanger方法是spi動態擴展,獲取所有exchange.Exchanger接口的實現類.這裏獲取到HeaderExchanger類.進入HeaderExchanger#bind()方法,代碼如下.*/
    return getExchanger(url).bind(url, handler);
}

HeaderExchanger#bind()方法代碼如下:

public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
	/*這裏的結構是嵌套的引用關係,HeaderExchangeServer內有Transporters類型的成員server.Transporters類內根據spi動態擴展獲取Transporter接口的實現類,dubbo默認是NettyServer類調用它的bind(),把DecodeHandler傳進去.DecodeHandler有ChannelHandler類型的成員指向HeaderExchangeHandler.HeaderExchangeHandler內有ExchangeHandler類型的成員指向DubboProtocol的請求處理類,即前面20處的ExchangeHandler,回調它的reply()方法,找到DubboExporter的invoke方法調用,如下面代碼所示*/
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

處理網絡請求的HeaderExchangeHandler#handleRequest()方法.

Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
	//創建返回請求的Response對象
    Response res = new Response(req.getId(), req.getVersion());
    ...
    // find handler by message class.
    Object msg = req.getData();
    try {
        // handle data.
        //調用前面20處的ExchangeHandler,回調它的reply()方法,找到DubboExporter的invoke方法調用
        Object result = handler.reply(channel, msg);
        res.setStatus(Response.OK);
        res.setResult(result);
    } catch (Throwable e) {
        res.setStatus(Response.SERVICE_ERROR);
        res.setErrorMessage(StringUtils.toString(e));
    }
    return res;
}

22.創建和zookeeper的連接.

來自上面的16處,進入ZookeeperRegistryFactory#createRegistry(),創建ZookeeperRegistry對象,連接zk,如下代碼所示:

public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
    ...
    String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
    if (!group.startsWith(Constants.PATH_SEPARATOR)) {
        group = Constants.PATH_SEPARATOR + group;
    }
    this.root = group;
    //連接zk
    zkClient = zookeeperTransporter.connect(url);
    //添加zk是否存活的監聽器
    zkClient.addStateListener(new StateListener() {
        public void stateChanged(int state) {
            if (state == RECONNECTED) {
                try {
                    recover();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    });
}

23.向zk註冊服務提供者.從上面16處進來.進入ZookeeperRegistryFactory#createRegistry()->ZookeeperRegistry#doRegister()
代碼如下:

protected void doRegister(URL url) {
    try {
    	/* 向zk請求創建路徑.路徑爲/dubbo/com.alibaba.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26side%3Dprovider%26timestamp%3D1584018965207.  
    	格式是 /dubbo/接口全路徑/providers/接口信息 */
        zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
    } catch (Throwable e) {
        throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章