dubbo源码分析5 -- ServiceBean 发布服务

发布服务 ServiceBean

发布入口

  • ServiceBean实现接口InitializingBean的afterPropertiesSet()方法.
public void afterPropertiesSet() throws Exception {
    //设置 provider,application,registries....
    //发布服务 
    if (!isDelay()) {
       export();
    }
}
  • 如果还没有发布服务,那么开始发布
public void onApplicationEvent(ApplicationEvent event) {
    if (ContextRefreshedEvent.class.getName().equals(
        event.getClass().getName())) {
    if (isDelay() && ! isExported() && ! isUnexported()) {
            export();
        }
    }
}

真正开始发布服务的是doExportUrls();


真正的开始发布服务

  • 获取注册中心的url地址
  • 循环协议,向协议注册url
private void doExportUrls() {
   //获取注册中心的url地址
   List<URL> registryURLs = loadRegistries(true);
   //<dubbo:protocol name="dubbo" port="20880" id="dubbo" />
   for (ProtocolConfig protocolConfig : protocols) {
       doExportUrlsFor1Protocol(protocolConfig, registryURLs);
   }
}

获取注册中心的url地址

<dubbo:registry protocol="zookeeper" address="10.118.22.25:2181" />
/**registry://224.5.6.7:1234/com.alibaba.dubbo.registry
          .RegistryService?application=demo-provider&dubbo=2.0.0&pid=2964
          &qos.port=22222&registry=multicast&timestamp=1523178188368
          **/
protected List<URL> loadRegistries(boolean provider) {
  List<URL> registryList = new ArrayList<URL>();
  if (registries != null && !registries.isEmpty()) {
      for (RegistryConfig config : registries) {
          String address = config.getAddress();
          Map<String, String> map = new HashMap<String, String>();
          //组装dubbo版本号、protocol为dubbo、application...
           registryList.add(url);
      }
  }
}

向协议注册url

a) 组装dubbo版本号、application、interface、methods以及ip地址和端口号
dubbo://10.118.14.178:20890/com.test.ITestService?anyhost=true&application=testservice&default.cluster=failfast&default.timeout=60000&dubbo=2.8.4
&generic=false
&interface=com.test.ITestService&logger=slf4j&methods=test,save&pid=8832&revision=1.0-SNAPSHOT&side=provider&timestamp=1523602774419&version=1.0.0

b)暴露服务
I) 如果有注册中心的话,将组装好的url地址组装成
registry://10.118.22.25:2181/com.alibaba.dubbo.registry.RegistryService?application=testservice&dubbo=2.8.4&export= dubbo://10.118.14.178:20890/com.test.ITestService?anyhost=true&application=testservice&default.cluster=failfast&default.timeout=60000&dubbo=2.8.4
&generic=false
&interface=com.test.ITestService&logger=slf4j&methods=test,save&pid=8832&revision=1.0-SNAPSHOT&side=provider&timestamp=1523602774419&version=1.0.0
走RegistryProtocol协议.
II) 没有没有注册中心,那么根据协议dubbo,走DubboProtocol

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, 
   List<URL> registryURLs) {
//组装url
    //默认是dubbo协议
    String name = protocolConfig.getName();
    if (name == null || name.length() == 0) {
        name = "dubbo";
    }
    Map<String, String> map = new HashMap<String, String>();
    //组装dubbo版本号、application、interface(com.alibaba.dubbo.demo.DemoService)
    //、side (provider)...
    //获取到接口中所有的方法名称
    String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames()
    //组装接口中的方法methods(sayHello)
HashSet<String>(Arrays.asList(methods)), ","));
    //组装绑定ip
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    //组装端口号20880
    Integer port = this.findConfigedPorts(protocolConfig, name, map);

    URL url = new URL(name, host, port, (contextPath == null 
    || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
    //<dubbo:protocol name="dubbo" port="20890" id="dubbo" />
    //如果协议是本地的话,那就不需要注册
    if ("injvm".equals(protocolConfig.getName())) {
       protocolConfig.setRegister(false);
        map.put("notify", "false");
    }
//暴露服务
    String scope = url.getParameter(Constants.SCOPE_KEY);
    //配置为none不暴露
    if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
        //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务)
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
            exportLocal(url);
        }
        //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露远程服务)
        if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){
            //走Registry协议
            if (registryURLs != null && registryURLs.size() > 0
                        && url.getParameter("register", true)) {   
               for (URL registryURL : registryURLs) {
                   Exporter<?> exporter = protocol.export(invoker);
                   exporters.add(exporter);
               }  
            }else {
                //走dubbo协议
                Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) 
                interfaceClass, url);
                Exporter<?> exporter = protocol.export(invoker);
                exporters.add(exporter);
            }
        }
    }
}

暴露本地服务, 不做操作

private void exportLocal(URL url) {
   if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
   /**组装本地的url 
   injvm://127.0.0.1/com.test.ITestService?anyhost=true&application=testService&
   default.cluster=failfast&default.timeout=60000&dubbo=2.8.4&generic=false
   &interface=com.test.ITestService&logger=slf4j&methods=
  test,save&version=1.0.0
   **/
       URL local = URL.valueOf(url.toFullString())
               .setProtocol("injvm")
               .setHost("127.0.0.1")
               .setPort(0);
      //将接口的实现类放入到ThreadLocal中com.test.ITestService
       ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));

       Exporter<?> exporter = protocol.export(
               proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
       exporters.add(exporter);
   }
}

获取主机ip绑定

1) 取dubbo:protocol中的host
2) 取本地地址InetAddress.getLocalHost().getHostAddress();
3)循环注册中心的地址,连接成功就是那个ip

private String findConfigedHosts(ProtocolConfig protocolConfig, 
   List<URL> registryURLs, Map<String, String> map) {
//1. <dubbo:protocol host="">
String host = protocolConfig.getHost();
 if (provider != null && (host == null || host.length() == 0)) {
     host = provider.getHost();
 }
 boolean anyhost = false;
 if (NetUtils.isInvalidLocalHost(host)) {
     anyhost = true;
     try {
        // 2. 获取本地
         host = InetAddress.getLocalHost().getHostAddress();
     } catch (UnknownHostException e) {
         logger.warn(e.getMessage(), e);
     }
     if (NetUtils.isInvalidLocalHost(host)) {
         //3.循环注册中心的地址,是否能连接
      if (registryURLs != null && registryURLs.size() > 0) {
         for (URL registryURL : registryURLs) {
            try {
               Socket socket = new Socket();
               try {
                   SocketAddress addr = new InetSocketAddress(registryURL.getHost(),
                    registryURL.getPort());
                   socket.connect(addr, 1000);
                   host = socket.getLocalAddress().getHostAddress();
                   break;
               } finally {
                   try {
                       socket.close();
                   } catch (Throwable e) {}
               }
            } catch (Exception e) {
                logger.warn(e.getMessage(), e);
            }
          }
      }
      if (NetUtils.isInvalidLocalHost(host)) {
          host = NetUtils.getLocalHost();
      }
   }
 }
   map.put("bind_ip", hostToBind);
}

猜你喜欢

转载自blog.csdn.net/liyue1090041509/article/details/79852847