dubbo源码理解(1)启动初始化与bean加载

今天看了一些博文,都是关于dubbo源码解析方面的。觉得有必要记一下。

问题1:spring 如何注入dubbo 的?或者说怎么集成dubbo 的,或者说 dubbo启动时怎么启动spring的?

1、首先想要实现 在spring 中 发挥某框架的功能,就必须将该框架注入到springBean 中。
2、dubbo 中 dubbo-container-spring 模块,类 spirngContainer 里面的start方法实现了这功能。
3、上述的start方法 由dubbo 的Main方法调用。。。
4、start方法执行时 会调用spring配置文件路径。如果没有配置Spring xml文件的路径,会默认加载classpath/META-INF下的spring/*.xml文件。

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 标签的?

1、首先要清楚,spring 原生的标签 比如一些注解,aop的。bean 的。为什么都能认识?
    是因为在命名空间中指定了对应的标签比如aop的 xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop"指定这两个,就可以使用aop的相关标签。

2、dubbo 也是一样(需要在spring配置文件中添加dubbo的命名空间)dubbo-config-spring包下的META-INF目录下spring.handlers和spring.schemas文件两个文件就是来处理命名空间和xsd。
spring 在识别命名空间时,使用的是NamespaceHandlerSupport抽象类和NamespaceHandler接口
而dubbo 的DubboNamespaceHandler 继承了NamespaceHandlerSupport,会在初始化时,加载并识别dubbo标签,启动dubbo的Main 方法时就加载了上述两个文件进而让spring知道自定义了NamespaceHandlerSupport;

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 的方法。

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 对象调用服务端方法使用;

*如果是dubbo:protocol标签,dubboh还会检查所有已经包含protocol属性的BeanDefinition且protocol属性对应的值是ProtocolConfig对象的bean,将其属性的protocol值设置成当前的bean引用:
     definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));

 *如果是dubbo服务提供者的dubbo:service标签,则还会设置ref属性为对应接口class的实现类bean:
         beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));

问题3:怎么注入的呢?

1、其实就是上面的DubboBeanDefinitionParser类,进行操作的,该类将dubbo:reference这种标签解析成spring能够管理的BeanDefinition对象(我喜欢叫容器,这货是一个map)
2、仔细看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补充:

1、在注入和生成动态代理的时候使用Javassist 其实生成的是一个字节码文件,保存在jvm缓存中,等待调用。

简要说明。对于提供者。就是spring 将dubbo标签通过ServiceConfig 解析成了ServiceBean,并生成好了一个invoker,该invoker放在exporter对象下,

exporter对象又放在exporters对象下,然后创建的nettyServer 放在了protocol(单例的)对象下的一个容器里,这样serviceBean 里面就有了可用的invoker(接收consumer 请求,执行自己的invoke方法,之后反射出业务类impl,执行业务代码,将结果通过netty通道返回),nettyServer,等待被调用。

注意:服务提供者在创建出invoker 后 执行业务类的时候使用的是反射技术。不是代理。消费者在执行时,使用代理对象执行invoke方法 才能实现远程调用。

猜你喜欢

转载自my.oschina.net/u/2543341/blog/2245128