美文网首页
1.1-服务提供者启动流程

1.1-服务提供者启动流程

作者: xhrg | 来源:发表于2018-12-26 11:08 被阅读0次

    一:入口

    • 在dubbo-2.5.3.jar中的META-INF下有一个文件是spring.handlers里面配置了一个类是com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,这个便是dubbo的入口。(原理可以看spring-schema扩展)
    public class DubboNamespaceHandler extends NamespaceHandlerSupport {
        static {
            Version.checkDuplicate(DubboNamespaceHandler.class);
        }
         // 这个类DubboNamespaceHandler 会把xml中配置的一些标签注册为bean解析器,比如说遇到provider这个字符串就会用下面对应的Parser去解析,所以下面的字符串application,module,registry都会对应到不同的Parse实例。
        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));
            //比如说配置了<dubbo:service ref="personService" interface="com.wang.dubbo.api.PersonService" protocol="dubbo" />
            //这个时候就会用DubboBeanDefinitionParser去解析这个标记,然后组装ServiceBean对象。
            registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
            registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
            registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
        }
    
    }
    

    如果遇到<dubbo:service ref="personService" interface="com.wang.dubbo.api.PersonService" protocol="dubbo" />,解析代码是在DubboBeanDefinitionParser的parse方法中,dubbo-2.5.3.jar的231行。

    beanDefinition.getPropertyValues().addPropertyValue(property, reference);

    这里的beanDefinition指的是RootBeanDefinition实例,内部的BeanClass是com.alibaba.dubbo.config.spring.ServiceBean,
    这里的property, reference分别是interface和com.wang.dubbo.api.PersonService。到此已经可以看到,解析成功,组装了ServiceBean。

    二:ServiceBean的启动

    • ServiceBean实现了众多的spring扩展点(InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware,扩展点主要是会在spring容器加载的时候,调用一些钩子方法)
    • ServiceBean中有2个比较核心的方法,是afterPropertiesSet,onApplicationEvent
    • ServiceBean还继承了很多类,这些类是链式的继承关系,每个类都包含了很多属性:如下:
      • ServiceBean
      • ServiceConfig
      • AbstractServiceConfig
      • AbstractInterfaceConfig
      • AbstractMethodConfig
      • AbstractConfig
      • Serializable
    2.1 afterPropertiesSet

    第一步,设置属性,包括:

    • setProvider(providerConfig);
    • setApplication(applicationConfig);
    • setModule(moduleConfig);
    • super.setRegistries(registryConfigs);
    • setMonitor(monitorConfig);
    • super.setProtocols(protocolConfigs);
    • setPath(beanName);
    2.2 onApplicationEvent

    该方法会调用export(); 实现真实的服务启动发布

    三:export方法

    export先做属性等的设置,然后做检查,最后调用doExportUrls。

    • 3.1 loadRegistries:先拿到所有的注册地址:List<URL> registryURLs = loadRegistries(true);,然后循环注册地址去注册
    • 3.2 doExportUrlsFor1Protocol: InetAddress.getLocalHost().getHostAddress();(获取本机Ip地址)
    • 3.3 获取本机ip地址,获取端口地址,获取方法名称,获取版本号,获取同步异步等信息组装成Map,然后根据Map生成url:比如说以下URL

    dubbo://192.168.122.23:20880/com.wang.dubbo.api.PersonService?anyhost=true&application=Dubbo_HelloWorld&dubbo=2.5.3&interface=com.wang.dubbo.api.PersonService&methods=say&pid=59448&side=provider&timestamp=1545891510122

    • 3.4 exportLocal:暴露本地服务(比如说jvm实例内部调用其实不需要走网络,所以这里会先放到本地)
      • 3.4.1 生成本地URL :injvm://127.0.0.1/com.wang.dubbo.api.PersonService?xxxxx(省略)
      • 3.4.2 根据实例(PersonServiceImpl,)接口,URL ,生成Invoker(详情见ProxyFactory:getInvoker),再往里面是JavassistProxyFactory|getInvoker获取Invoker。
      • 生成 Invoker后会包装成Exporter ,把Exporter 放在List<Exporter<?>> exporters中,该List是ServiceConfig的属性。
    • 3.5 暴露本地服务完了后会根据registryURLs暴露到相关地址上,比如说暴露到zk上。
      • 3.5.1 暴露远程服务也是一样的 Invoker<?> invoker = proxyFactory.getInvoker,Exporter<?> exporter = protocol.export(invoker);先根据proxyFactory获取代理对象,然后根据protocol暴露并且转化为Exporter。

    三:protocol.export(invoker) 方法

    • RegistryProtocol|export -> doLocalExport(originInvoker); 该调用会启动netty服务,监听请求。
    • 该方法会对应到一个实现是RegistryProtocol中的export,在这个方法中会读取zk信息,把URL写入ZK。到此过程中一个dubbo服务提供者发布完成。

    四:doLocalExport(RegistryProtocol|exporth)

    该方法调用到底层会调用到DubboProtocol的export,该方法内部会openServer。 openServer 会启动netty监听端口。
    大致的调用链如下(笔记的写法和eclipse的显示上下相反)

    • DubboProtocol:openServer
    • DubboProtocol:createServer
    • Exchangers:bind
    • HeaderExchanger:bind
    • Transporters:bind
    • NettyTransporter:bind
    • new NettyServer(url, listener); 到此接受请求就会进入NettyHandler(该类继承SimpleChannelHandler)

    当client调用的时候,拿到请求数据,会解析成Request,然后处理后返回,核心代码在HeaderExchangeHandler中

    Response response = handleRequest(exchangeChannel, request);

    AbstractProtocol的exporterMap会缓存Exporter,其中key是接口名+端口,比如说com.wang.dubbo.api.PersonService:20880,
    然后从Exporter中拿到invoker,invoker.invoke(Invocation inv);返回结果invoke到实际类调用中间会经过非常多的Filter。

    最后

    dubbo服务者发布过程中的很多信息,都会记录在该ServiceBean的属性中。

    相关文章

      网友评论

          本文标题:1.1-服务提供者启动流程

          本文链接:https://www.haomeiwen.com/subject/edthlqtx.html