dubbo源碼理解(1)啓動初始化與bean加載

今天看了一些博文,都是關於dubbo源碼解析方面的。以爲有必要記一下。java

問題1:spring 如何注入dubbo 的?或者說怎麼集成dubbo 的,或者說 dubbo啓動時怎麼啓動spring的?spring

一、首先想要實現 在spring 中 發揮某框架的功能,就必須將該框架注入到springBean 中。
二、dubbo 中 dubbo-container-spring 模塊,類 spirngContainer 裏面的start方法實現了這功能。
三、上述的start方法 由dubbo 的Main方法調用。。。
四、start方法執行時 會調用spring配置文件路徑。若是沒有配置Spring xml文件的路徑,會默認加載classpath/META-INF下的spring/*.xml文件。express

public void start() {
        String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
        if (configPath == null || configPath.length() == 0) {
            configPath = DEFAULT_SPRING_CONFIG;
        }
        context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
        context.start();
    }

問題2:spring 是如何識別dubbo 標籤的?apache

一、首先要清楚,spring 原生的標籤 好比一些註解,aop的。bean 的。爲何都能認識?
    是由於在命名空間中指定了對應的標籤好比aop的 xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop"指定這兩個,就可使用aop的相關標籤。緩存

二、dubbo 也是同樣(須要在spring配置文件中添加dubbo的命名空間)dubbo-config-spring包下的META-INF目錄下spring.handlers和spring.schemas文件兩個文件就是來處理命名空間和xsd。
spring 在識別命名空間時,使用的是NamespaceHandlerSupport抽象類和NamespaceHandler接口
而dubbo 的DubboNamespaceHandler 繼承了NamespaceHandlerSupport,會在初始化時,加載並識別dubbo標籤,啓動dubbo的Main 方法時就加載了上述兩個文件進而讓spring知道自定義了NamespaceHandlerSupport;app

DubboNamespaceHandler源碼框架

/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.config.spring.schema;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

import com.alibaba.dubbo.common.Version;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.ModuleConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.AnnotationBean;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;

/**
 * DubboNamespaceHandler
 * 
 * @author william.liangf
 * @export
 */
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

	static {
		Version.checkDuplicate(DubboNamespaceHandler.class);
	}

	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 DubboBeanDefinitionParser(AnnotationBean.class, true));
    }

}

進入registerBeanDefinitionParser的方法,能夠看到他是NamespaceHandlerSupport 的方法。less

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
}

第一個參數  是 元素名稱,就是告訴spring 我要解析注入這個標籤中的class 第二個參數DubboBeanDefinitionParser  實現了BeanDefinitionParser接口,而BeanDefinitionParser接口  是spring 將xml標籤解析成BeanDefinition對象的接口,因此DubboBeanDefinitionParser 就是將spring中dubbo 的標籤轉換成BeanDefinition對象,其元素名稱之後還要給Invoker 對象調用服務端方法使用;jvm

*若是是dubbo:protocol標籤,dubboh還會檢查全部已經包含protocol屬性的BeanDefinition且protocol屬性對應的值是ProtocolConfig對象的bean,將其屬性的protocol值設置成當前的bean引用:
     definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));ide

 *若是是dubbo服務提供者的dubbo:service標籤,則還會設置ref屬性爲對應接口class的實現類bean:
         beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));

 

問題3:怎麼注入的呢?

一、其實就是上面的DubboBeanDefinitionParser類,進行操做的,該類將dubbo:reference這種標籤解析成spring可以管理的BeanDefinition對象(我喜歡叫容器,這貨是一個map)
二、仔細看dubbo消費者 注入類型是ReferenceBean。其父類是ReferenceConfig 他的屬性:

private static finalProxyFactoryproxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
	 
	//接口類型
	private String interfaceName;
	 
	private Class<?> interfaceClass;
	 
	//接口代理類引用
	private transient volatileTref;
	 
	private transient volatileInvoker<?>invoker;

可知,dubbo 將標籤轉化爲對象的時候使用的是動態代理,這點與spring 的IOC大不同,,IOC是反射原理。

ReferenceConfig實現了FactoryBean接口 調用get方法返回代理對象,其子類ReferenceBean 再調用getObject(就是FactoryBean的方法),獲取代理對象。


那麼   dubbo使用的 是jdk 仍是cgLib呢?
cgLib沒有在使用的行列,不知道緣由。但,jdk 和Javassist 兩種卻被使用,默認使用Javassist動態代理模式(聽說效率很高)。可自定義使用jdk代理模式(因這種動態代理僅限接口,使用範圍受限,且效率不高,不多用)。

 

以上是小弟 從網上看到並實際操做實踐+本身一些理解的(已經看了很多,但不敢寫。怕理解有誤)。先記下來。有不穩當的地方後期完善。

 

2018-11-22補充:

一、在注入和生成動態代理的時候使用Javassist 其實生成的是一個字節碼文件,保存在jvm緩存中,等待調用。

簡要說明。對於提供者。就是spring 將dubbo標籤經過ServiceConfig 解析成了ServiceBean,並生成好了一個invoker,該invoker放在exporter對象下,

exporter對象又放在exporters對象下,而後建立的nettyServer 放在了protocol(單例的)對象下的一個容器裏,這樣serviceBean 裏面就有了可用的invoker(接收consumer 請求,執行本身的invoke方法,以後反射出業務類impl,執行業務代碼,將結果經過netty通道返回),nettyServer,等待被調用。

注意:服務提供者在建立出invoker 後 執行業務類的時候使用的是反射技術。不是代理。消費者在執行時,使用代理對象執行invoke方法 才能實現遠程調用。

相關文章
相關標籤/搜索