dubbo学习之源码

dubbo 官网

dubbo中文文档

准备工作

1 安装zookeeper 注册中心(dubbo 推荐使用)

2 dubbo 管理控制台(不安装也行)

idea 测试代码

分为三块:

公共接口模块--主要是一些bean 和要暴露的接口

服务提供者模块

服务消费者模块

--------------------------------------------------------------------------------------------------------------------

(1)首先服务提供者和服务消费者都需要依赖公共接口模块

在消费者和提供者的pom文件添加接口依赖

(2)在服务提供者和服务消费者pom文件中添加dubbo 和zookeeper依赖

1、引入dubbo
		<!-- 引入dubbo -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>dubbo</artifactId>
			<version>2.6.2</version>
		</dependency>
	<!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper:
          dubbo 2.6以前的版本引入zkclient操作zookeeper 
          dubbo 2.6及以后的版本引入curator操作zookeeper
          下面两个zk客户端根据dubbo版本2选1即可
    -->
		<dependency>
			<groupId>com.101tec</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.10</version>
		</dependency>
		<!-- curator-framework -->
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>2.12.0</version>
		</dependency>

(3)然后开始配置服务提供者xml

1>配置应用名称

2>配置注册中心

3>配置要暴露的服务接口

4> 配置普通bean的接口实现

5>配置dubbo的socket通信

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    <!--1-->
    <dubbo:application name="web_provider" organization="com.ecpss" owner="a"></dubbo:application>
<!--2-->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
    <!--3-->
    <dubbo:service interface="com.ecpss.service.HelloService" ref="service"></dubbo:service>
    <bean id="service" class="com.ecpss.impl.ServiceImpl"></bean>
<!--4-->
    <dubbo:service interface="com.ecpss.service.UserService" ref="users"></dubbo:service>
    <bean id="users" class="com.ecpss.impl.UserServiceImpl"></bean>
<!--5-->
    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />
</beans>

(4)配置消费者xml

1>配置应用名称

2>配置注册中心

3>配置接口的引用

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
         http://dubbo.apache.org/schema/dubbo
              http://dubbo.apache.org/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    <context:component-scan base-package="com.ecpss"></context:component-scan>
    <!--1-->

    <dubbo:application name="web_consumer" organization="com.ecpss" owner="a"></dubbo:application>
    <!--2-->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
    <!--3-->
    <dubbo:reference id="demo" interface="com.ecpss.service.HelloService"></dubbo:reference>
    <dubbo:reference interface="com.ecpss.service.UserService" id="user"></dubbo:reference>

    </beans>

dubbo测试结束 测试代码推送到github 链接  https://github.com/haobaxucan/dubbo01.git

 

源码分析

从 https://github.com/alibaba/dubbo 拉取dubbo源码

Person.class.newInstance().aa();//使用类反射创建对象调用方法aa()

dubbo原理:

Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑。

1.spring容器启动,加载资源文件的时候,解析标签,然后根据名称空间找到对应的handler

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

NamespaceHandlerResolver中的 resolve()方法进行解析,它的默认实现DefaultNamespaceHandlerResolver:

getHandlerMappings()方法会加载classpath下所有的"META-INF/spring.handlers"文件,并存放在handlerMappings(Map)中,在后续的解析xml自定义属性时会根据命名空间在handlerMappings中查找NamespaceHandler去解析:

这个和注意是所有的hanlder

public NamespaceHandler resolve(String namespaceUri) {
    //获取所有已经配置的handler映射  
    Map<String, Object> handlerMappings = getHandlerMappings();
    //根据命名空间找到对应的处理器对象或者Class
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    }
    else if (handlerOrClassName instanceof NamespaceHandler) {
        //是否是NamespaceHandler对象实例,所有的自定义命名空间处理器必须实现NamespaceHandler接口
        //以前已经生成处理器对象,直接返回缓存的处理器对象
        return (NamespaceHandler) handlerOrClassName;
    }
    else {
        //没有做过解析,则返回的是类路径  
        String className = (String) handlerOrClassName;
        try {
            //根据类路径加载处理器Class
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                        "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            //生成处理器对象
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            namespaceHandler.init();
            //以命名空间uri为key值,理器对象为value值,保存到一个map中
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }
}


代码主要通过调用getHandlerMappings()方法获得NamespaceHandler对象与命名空间URI的映射表,并从这个映射表中取出对象,判断是否已经生成了NamespaceHandler对象。若已生成NamespaceHandler对象,则立即返回该对象,否则生成NamespaceHandler对象,并把它存放到刚才的映射表中,这样下次再获取就不用再生成对象了。那何时建立NamespaceHandler对象与命名空间URI的映射呢?我们继续跟踪getHandlerMappings()方法


private Map<String, Object> getHandlerMappings() {
    if (this.handlerMappings == null) {
        synchronized (this) {
            if (this.handlerMappings == null) {
                try {
                    //handlerMappingsLocation默认为"META-INF/spring.handlers"
                    Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isDebugEnabled()) {
                    logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                    // 把Properties对象中的key-value复制到handlerMappings中
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                }
                catch (IOException ex) {
                    throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
            }
        }
    }
    return this.handlerMappings;
}

使用PropertiesLoaderUtils.loadAllProperties()从handlerMappingsLocation指定的handlers文件加载命名空间名称和具体NamespaceHandler之间的关联配置。handlerMappingsLocation默认的路径是jar包下的META-INF目录下的spring.handlers文件.

由此,当解析到http://www.springframework.org/schema/context命名空间时,PropertiesLoaderUtils.loadAllProperties()就会将以http://www.springframework.org/schema/context为key,org.springframework.context.config.ContextNamespaceHandler处理器类的全限定名作为value存进handlerMappings这个Map中。当第一次调用DefaultNamespaceHandlerResolver类,的resolve(String namespaceUri)方法获取到处理器类的全限定名,再根据处理器类的全限定名生成处理器对象,并把该对象保存进handlerMappings中,这样下一次再获取就不会生成对象了。这样就完成了命名空间处理器注册了。

链接地址

spring.bean包中springhanler 文件

这些自定义的NamespaceHandler都必须实现NamespaceHandler接口或继承NamespaceHandlerSupport.
如自定义的标签Dubbo比如:

以前是阿里巴巴的内部rpc框架,现在交给了apache托管

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    public DubboNamespaceHandler() {
    }

    public void init() {
        this.registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        this.registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        this.registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        this.registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        this.registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        this.registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        this.registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        this.registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        this.registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        this.registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

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

每一个标签都有相应的xxxconfig,比如application就会有applicationConfig

protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    this.parsers.put(elementName, parser);
}//调用相应的解析器将标签放在集合中

而每一种标签的解析都会有对应标签解析器如dubbo的DubboBeanDefinitionParser,下面就是开始dubbo 标签的解析。

dubbo每一种标签都有对应的配置,AbstractConfig是所有其它配置的父类,主要是一些标签的配置解析

ServiceConfig 服务提供者的配置  添加参数配置信息,且暴露服务

ReferenceConfig 服务消费者的配置 添加参数配置信息,且引用服务

----------------------------------------------------------------------------------------------------

运行dubbo服务
1.直接运行tomcat--浪费资源
2.自建main 加载spring配置文件---测试可用
3.使用dubbo 框架提供的Main方法---建议使用
优雅关机:不接受请求,如果线程池还有业务在运行,只等待业务执行完成

在Linux操作系统上手工部署Dubbo服务

消费端
1.打成war
2.如果是被依赖的模块需要构建(如--构建到本地)
3.环境变量
4.安装tomcat

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值