dubbo源码之启动、导出服务 v1.0

一.参考

二.架构
(一)分层架构
参考官网架构图 http://dubbo.apache.org/books/dubbo-dev-book/design.html
从消费端来说,从上到下依次是
1.Service层,用户定义的业务接口
2.Config层,读取用户配置(比如超时时间,group等),主要是ServiceConfig,ReferenceConfig.
3.Proxy层,因为用户定义的都是接口,消费端需要具体类对象才能调用。统一实现JDK动态代理或者cglib,向下层做调用.主要是ServiceProxy,ProxyFactory等.
4.Registry层,实现注册中心的对接,从注册中心拉取服务端,消费端地址列表.主要类为Registry,RegistryFactory,RegistryService等.
5.Cluster层,集群层,主要处理比如路由黑白名单,负载均衡,集群中机器挂掉,调用失败的重试策略等.主要类为Cluster,Directory,Router,LoadBalance.
6.Monitor层.统计监控层,主要接口是Statistics,MonitorFactory,MonitorService.
7.Protocol层,主要处理使用哪种协议,比如dubbo还是http等.主要接口是Invocation,Result,Protocol,消费端的Invoker,服务端的Exporter等.
8.Exchange层,封装请求为Request,Response格式.主要接口为Exchanger,ExchangeChannel,ExchangeClient,ExchangeServer等.
9.Transport层,处理区分不同的网络框架,比如Netty,mina,包含网络请求,编解码器等.主要接口是Message,Channel,Transporter,Client,Codec,Server
10.序列化层,序列化请求对象.主要接口为Serialization,ObjectInput,ObjectOutput,ThreadPool
(二)动态扩展
采用Microkernel +Plugin模式,Microkernel只负责组装Plugin,Dubbo自身的功能也是通过扩展点实现.在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔.具体的动态扩展源码后面新开贴分析.


三.源码分析
(一)spring启动,解析dubbo的xml.


1.spring启动时读取dubbo的xml配置文件,和读取普通的spring的xml配置文件是一样的。进入DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(),这个方法之前的逻辑参考之前写的帖子.这个方法里面循环遍历xml里面的所有标签.因为是自定义标签,每个标签都进入BeanDefinitionParserDelegate#parseCustomElement().这个方法先调用DefaultNamespaceHandlerResolver#resolve()查找这个xml的解析类为DubboNamespaceHandler.进入DubboNamespaceHandler#init()注册xml的每个标签的解析类.代码如下

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 AnnotationBeanDefinitionParser());
}

然后进入DubboBeanDefinitionParser#parse()解析xml中的xml标签.这里面会注册ApplicationConfig,RegistryConfig,ProtocolConfig,ServiceBean(用来处理dubbo:service标签)类等到DefaultListableBeanFactory#beanDefinitionMap().这里需要注意下解析标签的ServiceBean类.普通的标签由spring来处理,和dubbo没关系.ServiceBean会把xml中ref引用的bean name,从ApplicationContext中取出bean的定义.把ref引用bean的完整路径设置为ServiceBean的id和name,比如xxx.DemoService.这个ServiceBean作为独立的bean放到beanDefinitionMap中.


(二)服务端导出dubbo的service


1.在ServiceBean#setApplicationContext()里面把Spring里面的ApplicationContext设置到Dubbo的SpringExtensionFactory#contexts成员属性里面.然后调用AbstractApplicationContext#addApplicationListener把dubbo设置为spring的观察者.
2.真正从spring调用到dubbo导出服务的接口的是进入到ServiceBean#afterPropertiesSet回调里面.这个是spring创建dubbo的接口的bean,比如DemoService.调用getBean()时,传入的beanName是前面获取的的ref引用的完整路径.所有的ServiceBean填充完对象属性,开始做这个ServiceBean的初始化操作,回调ServiceBean#afterPropertiesSet()方法.
3.在ServiceBean#afterPropertiesSet()里面.把ApplicationConfig,RegistryConfig,ProtocolConfig设置到ServiceBean里面.
4.回调到ApplicationContextAware#setApplicationContext()里面.ServiceBean#onApplicationEvent().进入到ServiceConfig#doExport()方法.代码如下:

protected synchronized void doExport() {
    if (unexported) {
        throw new IllegalStateException("Already unexported!");
    }
    //已经导出过,直接返回
    if (exported) {
        return;
    }
    exported = true;
    if (interfaceName == null || interfaceName.length() == 0) {
        throw new IllegalStateException(" interface not allow null!");
    }
    /* 遍历ProviderConfig类的setXXX方法,然后调用.比如setQosPort(),具体的参数值从配置文件中取出.*/
    checkDefault();
    if (provider != null) {
        if (application == null) {
            application = provider.getApplication();
        }
        if (module == null) {
            module = provider.getModule();
        }
        if (registries == null) {
            registries = provider.getRegistries();
        }
        if (monitor == null) {
            monitor = provider.getMonitor();
        }
        if (protocols == null) {
            protocols = provider.getProtocols();
        }
    }
    if (module != null) {
        if (registries == null) {
            registries = module.getRegistries();
        }
        if (monitor == null) {
            monitor = module.getMonitor();
        }
    }
    if (application != null) {
        if (registries == null) {
            registries = application.getRegistries();
        }
        if (monitor == null) {
            monitor = application.getMonitor();
        }
    }
    if (ref instanceof GenericService) {
        interfaceClass = GenericService.class;
        if (StringUtils.isEmpty(generic)) {
            generic = Boolean.TRUE.toString();
        }
    } else {
        try {
        	//创建dubbo接口的Class对象
            interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                    .getContextClassLoader());
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        //基本的是不是接口的检查
        checkInterfaceAndMethods(interfaceClass, methods);
        //是不是xml里面ref引用的检查
        checkRef();
        generic = Boolean.FALSE.toString();
    }
    if (local != null) {
        if ("true".equals(local)) {
            local = interfaceName + "Local";
        }
        Class localClass;
        try {
            localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        if (!interfaceClass.isAssignableFrom(localClass)) {
            throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
        }
    }
    if (stub != null) {
        if ("true".equals(stub)) {
            stub = interfaceName + "Stub";
        }
        Class stubClass;
        try {
            stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        if (!interfaceClass.isAssignableFrom(stubClass)) {
            throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
        }
    }
    /* 遍历ApplicationConfig类的setXXX方法,然后调用.比如setQosPort(),具体的参数值从配置文件中取出.*/
    checkApplication();
    //检查Resistry层配置
    checkRegistry();
    //检查Protocol层配置
    checkProtocol();
    appendProperties(this);
    checkStubAndMock(interfaceClass);
    if (path == null || path.length() == 0) {
        path = interfaceName;
    }
    //导出服务,主要是向注册中心,比如zk节点上注册提供者dubbo接口的名称,路径,版本,ip等等.代码在后面分析
    doExportUrls();
    ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
    ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}

5.针对每种协议,导出接口url
进入ServiceConfig#doExportUrls().

private void doExportUrls() {
	//加载xml中配置的注册中心的配置,生成url,代码在后面6分析
    List registryURLs = loadRegistries(true);
    for (ProtocolConfig protocolConfig : protocols) {
    	//每个协议都导出到每个注册中心里面,代码后面7分析
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

6.创建注册的url地址
进入AbstractInterfaceConfig#loadRegistries.

protected List loadRegistries(boolean provider) {
    checkRegistry();
    List registryList = new ArrayList();
    //遍历所有的注册中心配置
    if (registries != null && registries.size() > 0) {
        for (RegistryConfig config : registries) {
            String address = config.getAddress();
            if (address == null || address.length() == 0) {
                address = Constants.ANYHOST_VALUE;
            }
            String sysaddress = System.getProperty("dubbo.registry.address");
            if (sysaddress != null && sysaddress.length() > 0) {
                address = sysaddress;
            }
            if (address != null && address.length() > 0
                    && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                Map map = new HashMap();
                //添加ApplicationConfig,对应接口的哪个应用
                appendParameters(map, application);
                //添加RegistryConfig,注册中心地址
                appendParameters(map, config);
                map.put("path", RegistryService.class.getName());
                map.put("dubbo", Version.getVersion());
                map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                if (ConfigUtils.getPid() > 0) {
                    map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                }
                if (!map.containsKey("protocol")) {
                	//扩展机制加载协议的实现类,没有配置的话默认使用dubbo协议
                    if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                        map.put("protocol", "remote");
                    } else {
                        map.put("protocol", "dubbo");
                    }
                }
                //根据map转成url格式
                List urls = UrlUtils.parseURLs(address, map);
                for (URL url : urls) {
                    url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                    //添加xml中的zookeeper地址
                    url = url.setProtocol(Constants.REGISTRY_PROTOCOL);

                    /*最后map转成url的格式为:
                    zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=1879&qos.port=22222×tamp=1583997678318
                    */
                    if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                            || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                        registryList.add(url);
                    }
                }
            }
        }
    }
    return registryList;
}

7.每种协议的导出 
进入ServiceConfig#doExportUrlsFor1Protocol(),代码如下:

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {

    /* 省略部分代码,主要是读取配置,生成 值为{side=provider, application=demo-provider, methods=sayHello, qos.port=22222, dubbo=2.0.0, pid=1879, interface=com.alibaba.dubbo.demo.DemoService, generic=false, timestamp=1583998111644} 的map  */
    ...

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

        //调用Wrapper#makeWrapper()动态生成dubbo接口的Wrapper封装类,在后面11处分析
        //method指向dubbo接口的所有方法.
        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
        ...
    }

    //获取注册中心的地址和端口号
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    /* 这里会加载Protocol扩展的实现类,代码在后面8分析*/
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    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);
    // don't export when none is configured
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

        // export to local if the config is not remote (export to remote only when config is remote)
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
        	//导出本地接口,同一个jvm进程,代码分析在后面的8
            exportLocal(url);
        }
        // export to remote if the config is not local (export to local only when config is 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,这里一般就是Zookeeper的url.因为这里都是一个ServiceBean进来的,只有一个接口.
                for (URL registryURL : registryURLs) {
                    url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                    //加载监控中心的URL.默认本机的2181端口.
                    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);
                    }
                    /* 创建远程dubbo调用的Invoker对象,和本地Injvm的过程类似,只是URL换了,进入10处. 返回的invoker还是JavassistProxyFactory创建的Invoker对象. */
                    Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    //封装远程dubbo调用的Invoker对象为DelegateProviderMetaDataInvoker格式.代码在后面15处.
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                    /*远程dubbo调用的DelegateProviderMetaDataInvoker转成Exporter导出,后面16处分析.
                    这里的Protocol还是三个实现类{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper},但是第一个传入的是RegistryProtocol.三个实现类逆序调用.所以最后进入的是RegistryProtocol#export()方法创建DestroyableExporter,后面16处分析.先进入ProtocolFilterWrapper.export()方法,后面13处分析.*/
                    Exporter exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            } else {
                Invoker invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                Exporter exporter = protocol.export(wrapperInvoker);
                exporters.add(exporter);
            }
        }
    }
    this.urls.add(url);
}

8.查找协议导出端口时,加载协议扩展.协议扩展后面新开贴分析.代码如下,这里传入的protocolConfig是xml里面配置的内容,name是dubbo,map是前面读取的xml配置.

private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map map) {
    Integer portToBind = null;

    // parse bind port from environment
    //读取环境变量里面配置的dubbo端口,不是xml配置的
    String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
    portToBind = parsePort(port);

    // if there's no bind port found from environment, keep looking up.
    if (portToBind == null) {
    	//这里读取到xml配置的端口
        portToBind = protocolConfig.getPort();
        if (provider != null && (portToBind == null || portToBind == 0)) {
            portToBind = provider.getPort();
        }
        /* 动态扩展加载Protocol的所有实现类,调用Protocol#getDefaultPort()方法。这里有三个实现类{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper}.先加载到ProtocolFilterWrapper类.ProtocolFilterWrapper的构造方法参数是Protocol对象,Protocol成员指向上一个Protocol实现类DubboProtocol.这一步通过ExtensionLoader#createExtension()方法实现.然后QosProtocolWrapper的成员指向ProtocolFilterWrapper.ProtocolListenerWrapper的成员指向QosProtocolWrapper.实际这里返回的是DubboProtocol的端口 这块新开贴分析源码  */
        final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
        if (portToBind == null || portToBind == 0) {
            portToBind = defaultPort;
        }
        if (portToBind == null || portToBind <= 0) {
            portToBind = getRandomPort(name);
            if (portToBind == null || portToBind < 0) {
                portToBind = getAvailablePort(defaultPort);
                putRandomPort(name, portToBind);
            }
            logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
        }
    }

    // save bind port, used as url's key later
    map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));

    // registry port, not used as bind port by default
    String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
    Integer portToRegistry = parsePort(portToRegistryStr);
    if (portToRegistry == null) {
        portToRegistry = portToBind;
    }

    return portToRegistry;
}

9.导出本地同一jvm进程的dubbo接口

private void exportLocal(URL url) {
    if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
    	/* 设置本地地址为 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=1879&qos.port=22222&side=provider×tamp=1583998111644 的格式 */
        URL local = URL.valueOf(url.toFullString())
                .setProtocol(Constants.LOCAL_PROTOCOL)
                .setHost(LOCALHOST)
                .setPort(0);

        /* 这里两步操作
        (1).proxyFactory.getInvoker()获取Invoker对象.ProxyFactory是spi动态扩展,进入ExtensionLoader#getExtension()方法。实现类只有一个StubProxyFactoryWrapper.它的构造方法传入的ProxyFactory是JavassistProxyFactory.所以先调用StubProxyFactoryWrapper#getInvoker()->JavassistProxyFactory#getInvoker()(代码在后面10分析)创建Invoker代表dubbo接口调用的信息,
        (2).protocol.export()也是动态扩展.这里还是三个实现类{QosProtocolWrapper,ProtocolListenerWrapper,ProtocolFilterWrapper}.InjvmProtocol在QosProtocolWrapper的构造方法里面传入.这里是逆序调用,先调用ProtocolFilterWrapper#export(代码在后面12分析)->ProtocolListenerWrapper#export()(在13分析)->QosProtocolWrapper#export()(启动Qos的Server)->InjvmProtocol#export().InjvmProtocol真正把Invoker对象转成Exporter对象导出,在14处分析。最终生成的是InjvmExporter被封装后的ListenerExporterWrapper. */
        Exporter exporter = protocol.export(
                proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
        exporters.add(exporter);
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    }
}

10.创建Invoker.Invoker是代理对象,代理dubbo接口.
(1).如果是本地jvm协议,进入JavassistProxyFactory#getInvoker().方法参数proxy是前面调用时的xml中配置的ref标签值,实现类DemoServiceImpl. type是接口 com.alibaba.dubbo.demo.DemoService,url是前面创建的local的Url值 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2434&qos.port=22222&side=provider×tamp=1584001039834.
(2).如果是远程dubbo调用,使用zk注册的,参数不一样。proxy不变,还是xml中ref标签引用的dubbo接口实现类,type不变,指向dubbo接口,url变成 registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222®istry=zookeeper×tamp=1584018965180 .
代码如下:


public  Invoker getInvoker(T proxy, Class type, URL url) {
    // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
    //这里的Wrapper是核心.封装了所有接口Class对象到实际对象的引用.成员在下面代码.这里的getWrapper()调到后面11处的动态创建Wrapper
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
    /* 创建匿名类对象,所有的调用都会转到Wrapper#invokeMethod()方法中去调用.所有的对象,方法名,方法的参数类型,参数值都封装在Warpper对象中。*/
    return new AbstractProxyInvoker(proxy, type, url) {
        @Override
        protected Object doInvoke(T proxy, String methodName,
                                  Class[] parameterTypes,
                                  Object[] arguments) throws Throwable {

            /* invokeMethod是在Wrapper类的makeWrapper()方法里面动态生成的.Wrapper类的成员里面有dubbo实现类,invokeMethod会调用到 真实实现类的方法里面。这里在模拟jdk的动态代理实现 */
            return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
        }
    };
}

这里返回的Invoker是个匿名内部类AbstractProxyInvoker.调用方法只有上面的doInvoke(),供外面的类调用.对象成员如下:
 

public abstract class AbstractProxyInvoker implements Invoker {
	//接口的实现类
    private final T proxy;
    //接口的Class对象
    private final Class type;
    //接口对应的注册中心url地址
    private final URL url;
    ...
}

Wrapper类的成员,核心方法是invokeMethod,它是在makeWrapper()方法里面动态生成的.

public abstract class Wrapper {
	//Class对象到实际实现对象的映射
    private static final Map, Wrapper> WRAPPER_MAP = new ConcurrentHashMap, Wrapper>(); //class wrapper map
    private static final String[] EMPTY_STRING_ARRAY = new String[0];
    private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
    private static final Wrapper OBJECT_WRAPPER = {...}
}

动态生成的Wrapper类反编译如下:

dubbo源码之启动、导出服务 v1.0_第1张图片

11.动态拼字串创建dubbo接口的封装类.模拟动态代理功能.
入参为dubbo接口的Class对象

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
    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); }");

    ...
    //类名为wrapper + 自增序号,比如Wrapper0
    long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
    //创建ClassGenerator对象
    ClassGenerator cc = ClassGenerator.newInstance(cl);
    cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
    cc.setSuperClass(Wrapper.class);
	...

    try {
    	//创建封装类的Class
        Class wc = cc.toClass();
        // setup static field.
      	...
        //add by feivirus
        //我自己加的,把Class对象打到文件里反编译
        Wrapper result = (Wrapper) wc.newInstance();
        String objName = getObjectName(result.getClass().getName());
        generateProxyClassFile(objName, new Class[]{result.getClass()});
        //add end
        return result;
    } catch (RuntimeException e) {
        ...
    }
}

12.建立Filter的过滤职责链,返回被内含Filter职责链的新的Invoker.这Invoker内部包含JavassistProxyFactory创建的Invoker.
进入ProtocolFilterWrapper#export()方法.代码如下:

public  Exporter export(Invoker invoker) throws RpcException {
	//如果是远程registry协议,进入这个分支.直接调用ProtocolListenerWrapper.export()
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    //如果本地jvm,进入这里(1)先创建一个Filter接口实现类的职责链,代码在下面.(2)protocol指向ProtocolListenerWrapper,代码13分析
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

private static  Invoker buildInvokerChain(final Invoker invoker, String key, String group) {
    Invoker last = invoker;
    /* 加载所有Filter接口的实现类,这里有EchoFilter,ClassLoaderFilter,GenericFilter,ContextFilter,TraceFilter,TimeoutFilter, MonitorFilter,ExceptionFilter八个*/
    List filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (filters.size() > 0) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker next = last;
            last = new Invoker() {
            	...
            	//集中式职责链,依次调用
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                ...
            };
        }
    }
    return last;
}

13.创建Exporter的观察者Listener.
进入ProtocolListenerWrapper#export().

public  Exporter export(Invoker invoker) throws RpcException {
	/* 如果是远程registry协议,进入这个分支.直接调用QosProtocolWrapper.export().启动QosServer.然后进入RegistryProtocol#export()后面16处分析. */
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    /* 本地jvm注册,进入这里.导出的Exporter的实现类为ListenerExporterWrapper。代码如下. 这里的protocol是动态扩展时构造方法传进来的,指向QosProtocolWrapper,所以调用QosProtocolWrapper#export()(本地jvm不启动qos servier.))->QosProtocolWrapper的protocol成员指向InjvmProtocol,在14处分析*/
    return new ListenerExporterWrapper(protocol.export(invoker),
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
public class ListenerExporterWrapper implements Exporter {
	//实际创建的Exporter引用, 指向InjvmExporter.
    private final Exporter exporter;

    private final List listeners;
 }

14.真正实现Invoker到Exporter的转换.这里导出的Exporter在上面13处封装成了ListenerExporterWrapper,最终导出就是ListenerExporterWrapper。
进入InjvmProtocol#export(),代码如下:

public  Exporter export(Invoker invoker) throws RpcException {
	/* 创建InjvmExporter返回. 这里的invoker指向前面12处新创建的包含filter过滤链的Invoker.*/
    return new InjvmExporter(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}

InjvmExporter继承自AbstractExporter。代码如下:

class InjvmExporter extends AbstractExporter {

    private final String key;
    //这里的key是dubbo接口的全路径名,比如xxx.xxx.DemoService. value是InjvmExporter对象的this自身.
    private final Map> exporterMap;
}
public abstract class AbstractExporter implements Exporter {
	/* 这里的Invoker指向12处新创建的包含filter过滤链的Invoker.这个Invoker包含JavassistProxyFactory创建的Invoker2。 Invoker2内的proxy指向dubbo接口的实现类,比如DemoServiceImpl*/
    private final Invoker invoker;

    private volatile boolean unexported = false;
}

15.远程Dubbo调用invoker包装类.

public class DelegateProviderMetaDataInvoker implements Invoker {
	//这里指向JavassistProxyFactory创建的Invoker对象.
    protected final Invoker invoker;
	//指向dubbo中xml配置的解析标签的ServiceBean对象本身.
    private ServiceConfig metadata;
}

16.远程dubbo调用的DelegateProviderMetaDataInvoker转成Exporter接口导出.
从上面13处QosProtocolWrapper.export()方法调用过来,进入RegistryProtocol#export().入参为上面的DelegateProviderMetaDataInvoker.代码如下:

public  Exporter export(final Invoker originInvoker) throws RpcException {
    //export invoker
    /*协议换成dubbo协议的url,即dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843&qos.port=22222&side=provider×tamp=1584018965207 导出,进入DubboProtocol#export(),导出dubbo协议的invoker,启动dubbo协议的本机的netty server等待连接.后面代码17处分析*/
    final ExporterChangeableWrapper exporter = doLocalExport(originInvoker);

    /*这里获取的url格式为zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222×tamp=1584018965180 */
    URL registryUrl = getRegistryUrl(originInvoker);

    //registry provider
    //进入ZookeeperRegistryFactory#createRegistry()创建和注册中心连接的zookeeper连接,代码在后面的22处分析
    final Registry registry = getRegistry(originInvoker);
    final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

    //to judge to delay publish whether or not
    boolean register = registedProviderUrl.getParameter("register", true);

    ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);

    if (register) {
    	//调用FailbackRegistry#register()向zk发出请求,添加节点路径,注册服务提供者,在后面23处分析.
        register(registryUrl, registedProviderUrl);
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }

    // Subscribe the override data
    // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover.
    final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
    //Ensure that a new exporter instance is returned every time export
    return new DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}

17.导出dubbo协议的invoker.
进入DubboProtocol#export(),这里传入的invoker为ProtocolFilterWrapper包装过的invoker.代码如下:

public  Exporter export(Invoker invoker) throws RpcException {
	//取出dubbo协议的url,dubbo:xxx,前面16处有.
    URL url = invoker.getUrl();

    // export service.
    //创建key字串为com.alibaba.dubbo.demo.DemoService:20880
    String key = serviceKey(url);
    DubboExporter exporter = new DubboExporter(invoker, key, exporterMap);
    exporterMap.put(key, exporter);

    //export an stub service for dispatching 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."));
            }
        } else {
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }
    /* 启动dubbo服务器.DubboProtocol有成员serverMap,key是192.168.0.131:20880格式的地址,value是DubboProtocol#createServer()方法创建的ExchangeServer对象,代码在后面19处分析 */
    openServer(url);
    //返回DubboExporter
    return exporter;
}

18.DubboExporter类,继承自AbstractExporter,代码在前面14处,含有invoker成员.

public class DubboExporter extends AbstractExporter {
	//字串为com.alibaba.dubbo.demo.DemoService:20880
    private final String key;
    //key是上面的key,value是DubboExporter对象本身.
    private final Map> exporterMap;
}

19.启动dubbo的ExchangeServer。

private ExchangeServer createServer(URL url) {
    ...
    ExchangeServer server;
    try {
    	/* url 为dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&channel.readonly.sent=true&codec=dubbo&dubbo=2.0.0&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843&qos.port=22222&side=provider×tamp=1584018965207 格式.
    	绑定地址.
    	requestHandler是dubbo协议的请求处理类,是ExchangeHandlerAdapter类型的DubboProtocol匿名内部类的成员变量,代码在后面你的20处.bind()方法进入后面的21处分析.*/
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
    str = url.getParameter(Constants.CLIENT_KEY);
    if (str != null && str.length() > 0) {
        Set supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
        if (!supportedTypes.contains(str)) {
            throw new RpcException("Unsupported client type: " + str);
        }
    }
    return server;
}

20.DubboProtocol的请求处理类

ExchangeHandlerAdapter类的reply回调方法,代码如下:
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
    if (message instanceof Invocation) {
        Invocation inv = (Invocation) message;
        /* 根据接口的serviceKey从exporterMap成员中找到对应的DubboExporter对象直接调用.serviceKey是com.alibaba.dubbo.demo.DemoService:20880格式,包含了接口的类型.*/
        Invoker invoker = getInvoker(channel, inv);
        // need to consider backward-compatibility if it's a callback
        ...
        RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
        //调用DubboExporter的invoke方法,执行dubbo接口的代理方法.
        return invoker.invoke(inv);
    }
    throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}

21.绑定ExchangeServer
进入exchange.Exchangers#bind().传入的url为上面19处的url.代码如下:

public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    ...
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    /*这里的getExchanger方法是spi动态扩展,获取所有exchange.Exchanger接口的实现类.这里获取到HeaderExchanger类.进入HeaderExchanger#bind()方法,代码如下.*/
    return getExchanger(url).bind(url, handler);
}

HeaderExchanger#bind()方法代码如下:

public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
	/*这里的结构是嵌套的引用关系,HeaderExchangeServer内有Transporters类型的成员server.Transporters类内根据spi动态扩展获取Transporter接口的实现类,dubbo默认是NettyServer类调用它的bind(),把DecodeHandler传进去.DecodeHandler有ChannelHandler类型的成员指向HeaderExchangeHandler.HeaderExchangeHandler内有ExchangeHandler类型的成员指向DubboProtocol的请求处理类,即前面20处的ExchangeHandler,回调它的reply()方法,找到DubboExporter的invoke方法调用,如下面代码所示*/
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

处理网络请求的HeaderExchangeHandler#handleRequest()方法.

Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
	//创建返回请求的Response对象
    Response res = new Response(req.getId(), req.getVersion());
    ...
    // find handler by message class.
    Object msg = req.getData();
    try {
        // handle data.
        //调用前面20处的ExchangeHandler,回调它的reply()方法,找到DubboExporter的invoke方法调用
        Object result = handler.reply(channel, msg);
        res.setStatus(Response.OK);
        res.setResult(result);
    } catch (Throwable e) {
        res.setStatus(Response.SERVICE_ERROR);
        res.setErrorMessage(StringUtils.toString(e));
    }
    return res;
}

22.创建和zookeeper的连接.

来自上面的16处,进入ZookeeperRegistryFactory#createRegistry(),创建ZookeeperRegistry对象,连接zk,如下代码所示:

public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
    ...
    String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
    if (!group.startsWith(Constants.PATH_SEPARATOR)) {
        group = Constants.PATH_SEPARATOR + group;
    }
    this.root = group;
    //连接zk
    zkClient = zookeeperTransporter.connect(url);
    //添加zk是否存活的监听器
    zkClient.addStateListener(new StateListener() {
        public void stateChanged(int state) {
            if (state == RECONNECTED) {
                try {
                    recover();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }
    });
}

23.向zk注册服务提供者.从上面16处进来.进入ZookeeperRegistryFactory#createRegistry()->ZookeeperRegistry#doRegister()
代码如下:

protected void doRegister(URL url) {
    try {
    	/* 向zk请求创建路径.路径为/dubbo/com.alibaba.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26side%3Dprovider%26timestamp%3D1584018965207.  
    	格式是 /dubbo/接口全路径/providers/接口信息 */
        zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
    } catch (Throwable e) {
        throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

 

你可能感兴趣的:(Java后台及存储,dubbo,源码,spring,spi扩展,导出)