dubbo 服务导出

NettyServer启动(注意这里要区分NettyClient) handler包装过程
默认AllDipacher AllChannelHandler FixThreadPool

protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {
	return new MultiMessageHandler(
			new HeartbeatHandler(
					ExtensionLoader.getExtensionLoader(Dispather.class).getAdaptiveExtension().dispath(handler, url)
			));
}

这还有一堆

public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
	return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

整理一下handler链

NettyServer
    .MultiMessageHandler
        .HeartbeatHandler //心跳检测
            .AllChannelHandler
                .TheadPoolExcutor //线程池
                .DecodeHandler
                    .HeaderExchangeHandler
                        .DubboProtocol  //这里是业务逻辑和通信的分割线
测试代码入口

用HelloService举例, 从com.alibaba.dubbo.config.ServiceConfig#export进入dubbo服务导出源码

public class Provider {
    public static void main(String[] args) throws IOException {
        ApplicationConfig applicationConfig = new ApplicationConfig("demo");
        ProtocolConfig protocolConfig = new ProtocolConfig("dubbo");
        protocolConfig.setPort(20881);

        RegistryConfig registryConfig = new RegistryConfig("localhost:2181");
        registryConfig.setProtocol("zookeeper");
        registryConfig.setGroup("demo");

        init(applicationConfig, protocolConfig, registryConfig, new SyncHelloService(), "sync");

        System.in.read();
    }

    private static void init(ApplicationConfig applicationConfig, ProtocolConfig protocolConfig, RegistryConfig registryConfig, HelloService instance, String group) {
        ServiceConfig helloService = new ServiceConfig();
        helloService.setApplication(applicationConfig);
        helloService.setProtocol(protocolConfig);
        helloService.setRegistry(registryConfig);
        helloService.setInterface(HelloService.class);
        helloService.setRef(instance);
        helloService.setGroup(group);
        helloService.setVersion("1.0.0");
        
        //export 是服务导出入口
        helloService.export();
    }
}

一堆配置检查 没什么好看的 最后进入doExport方法

    public synchronized void export() {
        if (provider != null) {
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {
                delay = provider.getDelay();
            }
        }
        if (export != null && ! export.booleanValue()) {
            return;
        }
        if (delay != null && delay > 0) {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(delay);
                    } catch (Throwable e) {
                    }
                    doExport();
                }
            });
            thread.setDaemon(true);
            thread.setName("DelayExportServiceThread");
            thread.start();
        } else {
            doExport();
        }
    }

加载注册中心URL 在每个注册中都注册一遍服务

注册中心URL示例:
registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo&dubbo=3.2.2&group=asyncdemo&pid=14476®istry=zookeeper×tamp=1562576090107

private void doExportUrls() {
        List registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }
3 组装URL

这个方法有两百多行 其实做的事情并不多
把各种信息放在map里面 比如side/版本/时间戳/进程号
比较核心的操作是

        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();

生成了一个wrapper类,wrapper包装了接口的实际实现

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
	String name = protocolConfig.getName();
	if (name == null || name.length() == 0) {
		name = "dubbo";
	}

	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 {
			host = InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			logger.warn(e.getMessage(), e);
		}
		if (NetUtils.isInvalidLocalHost(host)) {
			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();
			}
		}
	}

	Integer port = protocolConfig.getPort();
	if (provider != null && (port == null || port == 0)) {
		port = provider.getPort();
	}
	final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
	if (port == null || port == 0) {
		port = defaultPort;
	}
	if (port == null || port <= 0) {
		port = getRandomPort(name);
		if (port == null || port < 0) {
			port = NetUtils.getAvailablePort(defaultPort);
			putRandomPort(name, port);
		}
		logger.warn("Use random available port(" + port + ") for protocol " + name);
	}

	Map map = new HashMap();
	if (anyhost) {
		map.put(Constants.ANYHOST_KEY, "true");
	}
	map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
	map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
	map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
	if (ConfigUtils.getPid() > 0) {
		map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
	}
	appendParameters(map, application);
	appendParameters(map, module);
	appendParameters(map, provider, Constants.DEFAULT_KEY);
	appendParameters(map, protocolConfig);
	appendParameters(map, this);
	if (methods != null && methods.size() > 0) {
		for (MethodConfig method : methods) {
			appendParameters(map, method, method.getName());
			String retryKey = method.getName() + ".retry";
			if (map.containsKey(retryKey)) {
				String retryValue = map.remove(retryKey);
				if ("false".equals(retryValue)) {
					map.put(method.getName() + ".retries", "0");
				}
			}
			List arguments = method.getArguments();
			if (arguments != null && arguments.size() > 0) {
				for (ArgumentConfig argument : arguments) {
					//类型自动转换.
					if(argument.getType() != null && argument.getType().length() >0){
						Method[] methods = interfaceClass.getMethods();
						//遍历所有方法
						if(methods != null && methods.length > 0){
							for (int i = 0; i < methods.length; i++) {
								String methodName = methods[i].getName();
								//匹配方法名称,获取方法签名.
								if(methodName.equals(method.getName())){
									Class[] argtypes = methods[i].getParameterTypes();
									//一个方法中单个callback
									if (argument.getIndex() != -1 ){
										if (argtypes[argument.getIndex()].getName().equals(argument.getType())){
											appendParameters(map, argument, method.getName() + "." + argument.getIndex());
										}else {
											throw new IllegalArgumentException("argument config error : the index attribute and type attirbute not match :index :"+argument.getIndex() + ", type:" + argument.getType());
										}
									} else {
										//一个方法中多个callback
										for (int j = 0 ;j argclazz = argtypes[j];
											if (argclazz.getName().equals(argument.getType())){
												appendParameters(map, argument, method.getName() + "." + j);
												if (argument.getIndex() != -1 && argument.getIndex() != j){
													throw new IllegalArgumentException("argument config error : the index attribute and type attirbute not match :index :"+argument.getIndex() + ", type:" + argument.getType());
												}
											}
										}
									}
								}
							}
						}
					}else if(argument.getIndex() != -1){
						appendParameters(map, argument, method.getName() + "." + argument.getIndex());
					}else {
						throw new IllegalArgumentException("argument config must set index or type attribute.eg:  or ");
					}

				}
			}
		} // end of methods for
	}

	if (generic) {
		map.put("generic", String.valueOf(true));
		map.put("methods", Constants.ANY_VALUE);
	} else {
		String revision = Version.getVersion(interfaceClass, version);
		if (revision != null && revision.length() > 0) {
			map.put("revision", revision);
		}

		String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
		if(methods.length == 0) {
			logger.warn("NO method found in service interface " + interfaceClass.getName());
			map.put("methods", Constants.ANY_VALUE);
		}
		else {
			map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
		}
	}
	if (! ConfigUtils.isEmpty(token)) {
		if (ConfigUtils.isDefault(token)) {
			map.put("token", UUID.randomUUID().toString());
		} else {
			map.put("token", token);
		}
	}
	if ("injvm".equals(protocolConfig.getName())) {
		protocolConfig.setRegister(false);
		map.put("notify", "false");
	}
	// 导出服务
	String contextPath = protocolConfig.getContextpath();
	if ((contextPath == null || contextPath.length() == 0) && provider != null) {
		contextPath = provider.getContextpath();
	}
	URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

	if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
			.hasExtension(url.getProtocol())) {
		url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
				.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
	}

	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) ){
			if (logger.isInfoEnabled()) {
				logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
			}
			if (registryURLs != null && registryURLs.size() > 0
					&& url.getParameter("register", true)) {
				for (URL registryURL : registryURLs) {
					url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
					URL monitorUrl = loadMonitor(registryURL);
					if (monitorUrl != null) {
						url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
					}
					if (logger.isInfoEnabled()) {
						logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
					}
					Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));

					Exporter exporter = protocol.export(invoker);
					exporters.add(exporter);
				}
			} else {
				Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

				Exporter exporter = protocol.export(invoker);
				exporters.add(exporter);
			}
		}
	}
	this.urls.add(url);
}
4.生成wapper类 使用javasisit技术 动态生成wrapper类,一个wrapper类和一个接口对应,注意说的这里是接口,意味着就算有多个实现,也只生成一个wrapper类
4.1 缓存逻辑,避免重复创建
public static Wrapper getWrapper(Class c)
{
    while( ClassGenerator.isDynamicClass(c) ) // can not wrapper on dynamic class.
        c = c.getSuperclass();

    if( c == Object.class )
        return OBJECT_WRAPPER;

    Wrapper ret = WRAPPER_MAP.get(c);
    if( ret == null )
    {
        ret = makeWrapper(c);
        WRAPPER_MAP.put(c,ret);
    }
    return ret;
}

4.2 生成动态wrapper
使用javasisit技术 生成某个接口对应的wrapper
代码比较长 可以先看看最终生成的wrapper长什么样

HelloService 对应的wrapper
关键是invokeMethod方法 把通用的invoke请求参数 链接到实现类的对象(第一个参数)对应的方法上
一个映射工作,为什么要花这么多逻辑去生成动态代码,这样的好处是运行是就没有必要再通过反射去调用方法了,毕竟用户只关心请求响应时间,不会关心服务启动时间.

public class Wrapper1 extends Wrapper implements DC {
    public static String[] pns;
    public static Map pts;
    public static String[] mns;
    public static String[] dmns;
    public static Class[] mts0;
    public static Class[] mts1;

    public String[] getPropertyNames() {
        return pns;
    }

    public boolean hasProperty(String var1) {
        return pts.containsKey(var1);
    }

    public Class getPropertyType(String var1) {
        return (Class)pts.get(var1);
    }

    public String[] getMethodNames() {
        return mns;
    }

    public String[] getDeclaredMethodNames() {
        return dmns;
    }

    public void setPropertyValue(Object var1, String var2, Object var3) {
        try {
            SyncHelloService var4 = (SyncHelloService)var1;
        } catch (Throwable var6) {
            throw new IllegalArgumentException(var6);
        }

        throw new NoSuchPropertyException("Not found property \"" + var2 + "\" filed or setter method in class qunar.tc.dubbo.async.provider.SyncHelloService.");
    }

    public Object getPropertyValue(Object var1, String var2) {
        try {
            SyncHelloService var3 = (SyncHelloService)var1;
        } catch (Throwable var5) {
            throw new IllegalArgumentException(var5);
        }

        throw new NoSuchPropertyException("Not found property \"" + var2 + "\" filed or getter method in class qunar.tc.dubbo.async.provider.SyncHelloService.");
    }

    public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException {
        SyncHelloService var5;
        try {
            var5 = (SyncHelloService)var1;
        } catch (Throwable var8) {
            throw new IllegalArgumentException(var8);
        }

        try {
            if ("main".equals(var2) && var3.length == 1) {
                SyncHelloService.main((String[])var4[0]);
                return null;
            }

            if ("sayHello".equals(var2) && var3.length == 1) {
                return var5.sayHello((String)var4[0]);
            }
        } catch (Throwable var9) {
            throw new InvocationTargetException(var9);
        }

        throw new NoSuchMethodException("Not found method \"" + var2 + "\" in class qunar.tc.dubbo.async.provider.SyncHelloService.");
    }

    public Wrapper1() {
    }
}

makeWrapper 源码

	private static Wrapper makeWrapper(Class c)
	{
		if( c.isPrimitive() )
			throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);

		String name = c.getName();
		ClassLoader cl = ClassHelper.getClassLoader(c);

		StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
		StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
		StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");

		c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
		c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
		c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");

		Map> pts = new HashMap>(); // 
		Map ms = new LinkedHashMap(); // 
		List mns = new ArrayList(); // method names.
		List dmns = new ArrayList(); // declaring method names.
        Set getters = new HashSet(ms.keySet().size());
        Set setters = new HashSet(ms.keySet().size());
		
		// get all public field.
		for( Field f : c.getFields() )
		{
			String fn = f.getName();
			Class ft = f.getType();
			if( Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()) )
				continue;

			c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
			c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
			pts.put(fn, ft);
            getters.add(fn);
            setters.add(fn);
		}
		
		Method[] methods = c.getMethods();
		// get all public method.
		boolean hasMethod = hasMethods(methods);
		if( hasMethod ){
		    c3.append(" try{");
		}
		for( Method m : methods )
		{
			if( m.getDeclaringClass() == Object.class ) //ignore Object's method.
				continue;

			String mn = m.getName();
			c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
            int len = m.getParameterTypes().length;
            c3.append(" && ").append(" $3.length == ").append(len);
			
			boolean override = false;
			for( Method m2 : methods ) {
				if (m != m2 && m.getName().equals(m2.getName())) {
					override = true;
					break;
				}
			}
			if (override) {
				if (len > 0) {
					for (int l = 0; l < len; l ++) {
						c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
							.append(m.getParameterTypes()[l].getName()).append("\")");
					}
				}
			}
			
			c3.append(" ) { ");
			
			if( m.getReturnType() == Void.TYPE )
				c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
			else
				c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");

			c3.append(" }");
			
			mns.add(mn);
			if( m.getDeclaringClass() == c )
				dmns.add(mn);
			ms.put(ReflectUtils.getDesc(m), m);
		}
		if( hasMethod ){
		    c3.append(" } catch(Throwable e) { " );
		    c3.append("     throw new java.lang.reflect.InvocationTargetException(e); " );
	        c3.append(" }");
        }
		
		c3.append(" throw new ").append(NoSuchMethodException.class.getName()).append("(\"Not found method \\\"\"+$2+\"\\\" in class ").append(c.getName()).append(".\"); }");

		// deal with get/set method.
		Matcher matcher;
		for( Map.Entry entry : ms.entrySet() )
		{
			String md = entry.getKey();
			Method method = entry.getValue();
			if( ( matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				String pn = propertyName(matcher.group(1));
				c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
				pts.put(pn, method.getReturnType());
                getters.add(pn);
			}
			else if( ( matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				String pn = propertyName(matcher.group(1));
				c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
				pts.put(pn, method.getReturnType());
                setters.add(pn);
			}
			else if( ( matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md) ).matches() )
			{
				Class pt = method.getParameterTypes()[0];
				String pn = propertyName(matcher.group(1));
				c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt,"$3")).append("); return; }");
                pts.put(pn, pt);
                setters.add(pn);
            }
		}
		c1.append(" throw new ").append(NoSuchPropertyException.class.getName()).append("(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class ").append(c.getName()).append(".\"); }");
		c2.append(" throw new ").append(NoSuchPropertyException.class.getName()).append("(\"Not found property \\\"\"+$2+\"\\\" filed or getter method in class ").append(c.getName()).append(".\"); }");

		// make class
		long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
		ClassGenerator cc = ClassGenerator.newInstance(cl);
		cc.setClassName( ( Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw" ) + id );
		cc.setSuperClass(Wrapper.class);

		cc.addDefaultConstructor();
		cc.addField("public static String[] pns;"); // property name array.
		cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
		cc.addField("public static String[] mns;"); // all method name array.
		cc.addField("public static String[] dmns;"); // declared method name array.
		for(int i=0,len=ms.size();i> modifiedPts = new HashMap>();
        for (Map.Entry> entry : pts.entrySet()) {
            String propertyName = entry.getKey();
            if (getters.contains(propertyName) && setters.contains(propertyName)) {
                modifiedPts.put(propertyName, entry.getValue());
            }
        }
        try
		{
			Class wc = cc.toClass();
			// setup static field.
			wc.getField("pts").set(null, modifiedPts);
			wc.getField("pns").set(null, modifiedPts.keySet().toArray(new String[0]));
			wc.getField("mns").set(null, mns.toArray(new String[0]));
			wc.getField("dmns").set(null, dmns.toArray(new String[0]));
			int ix = 0;
			for( Method m : ms.values() )
				wc.getField("mts" + ix++).set(null, m.getParameterTypes());
			return (Wrapper)wc.newInstance();
		}
		catch(RuntimeException e)
		{
			throw e;
		}
		catch(Throwable e)
		{
			throw new RuntimeException(e.getMessage(), e);
		}
		finally
		{
			cc.release();
			ms.clear();
			mns.clear();
			dmns.clear();
		}
	}
4.3 本地服务导出

入口

exportLocal(url);

exportLocal Protocol 默认是 DubboProtocol

private void exportLocal(URL url) {
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(NetUtils.LOCALHOST)
                    .setPort(0);
            Exporter exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() +" to local registry");
        }
    }

上面说了wrapper封装了实际实现
这里又用了invoker去封装wrapper

public  Invoker getInvoker(T proxy, Class type, URL url) {
    // TODO Wrapper类不能正确处理带$的类名
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
    return new AbstractProxyInvoker(proxy, type, url) {
        @Override
        protected Object doInvoke(T proxy, String methodName, 
                                  Class[] parameterTypes, 
                                  Object[] arguments) throws Throwable {
            return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
        }
    };
}

protocal的export方法,导出一个invoker

public  Exporter export(Invoker invoker)

DubboProtocol的实现

    public  Exporter export(Invoker invoker) throws RpcException {
        URL url = invoker.getUrl();

        // export service.
        String key = serviceKey(url);
        DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);

        logger.debug("exported key:" + key + " -> " + invoker + "");

        exporterMap.put(key, exporter);

        //export an stub service for dispaching event
        Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
        Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
        if (isStubSupportEvent && !isCallbackservice) {
            String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
            if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
                if (logger.isWarnEnabled()) {
                    logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                            "], has set stubproxy support event ,but no stub methods founded."));
                }
            }
//                stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }

        openServer(url);

        return exporter;
    }
4.4 远程服务导出

操作流程比较长 就不列出调用链了

  1. 通过ServerBootstrap创建Server
  2. 把nettyHandler绑定在netty channel上,这样当netty channel有事件进来就会调用nettyHandler , nettyHandler绑定组装好的dubbo ChannelHandler链
  3. ChannelHandler链里的HeaderExchangeHandler会把消息转给.DefaultFuture#doReceived去处理
  4. doReceived源码: 给返回赋值 并解开阻塞条件变量done上的线程
private void doReceived(Response res) {
    lock.lock();
    try {
        response = res;
        if (done != null) {
            done.signal();
        }
    } finally {
        lock.unlock();
    }
    if (callback != null) {
        invokeCallback(callback);
    }
}

开启nettyServer 源码

    protected void doOpen() throws Throwable {
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
        bootstrap = new ServerBootstrap(channelFactory);
        
        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        channels = nettyHandler.getChannels();
        // https://issues.jboss.org/browse/NETTY-365
        // https://issues.jboss.org/browse/NETTY-379
        // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec() ,getUrl(), NettyServer.this);
                ChannelPipeline pipeline = Channels.pipeline();
                /*int idleTimeout = getIdleTimeout();
                if (idleTimeout > 10000) {
                    pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
                }*/
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
        // bind
        channel = bootstrap.bind(getBindAddress());
    }
5.服务注册

默认使用ZK注册 关键就这一句 使用apache提供zk客户端org.apache.curator.framework.CuratorFramework创建临时节点

public void createEphemeral(String path) {
    try {
        // 通过 Curator 框架创建节点
        client.create().withMode(CreateMode.EPHEMERAL).forPath(path);
    } catch (NodeExistsException e) {
    } catch (Exception e) {
        throw new IllegalStateException(e.getMessage(), e);
    }
}

临时节点数据示例
``
consumer://127.0.0.1/com.zc.IhelloService?active=false&category=consumers&check=false&cluster=failfast&connected=true&default.qloglevel=4&dubbo=3.2.24&interface=com.zc.IhelloService&methods=sayHello

dubbo://127.0.0.1/com.zc.IhelloService?active=false&category=consumers&check=false&cluster=failfast&connected=true&default.qloglevel=4&dubbo=3.2.24&interface=com.zc.IhelloService&methods=sayHello

你可能感兴趣的:(dubbo 服务导出)