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

一.参考

https://cn.dubbo.apache.org/zh-cn/

dubbo spi的分析参考之前写的文章.

分析的代码版本为dubbo-2.7.X.

二.架构


(一)分层架构


参考官网架构图 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等.消费端的接口的url到生产端的接口实现类在这里映射,存在org.apache.dubbo.rpc.protocol.dubbo.DubboExporter#delegateExporterMap中,key是url,value是接口的代理对象.
8.Exchange层,封装请求为Request,Response格式.主要接口为Exchanger,ExchangeChannel,ExchangeClient,ExchangeServer等.
9.Transport层,处理区分不同的网络框架,比如Netty,mina,包含网络请求,编解码器等.主要接口是Message,Channel,Transporter,Client,Codec,Server
10.序列化层,序列化请求对象.主要接口为Serialization,ObjectInput,ObjectOutput,ThreadPool

三.测试代码

1.服务端入口dubbo-demo的jar包下org.apache.dubbo.demo.provider.Application#main测试用例


四.源码分析


(一)spring启动


1.spring启动时读取dubbo的xml配置文件,和读取普通的spring的xml配置文件是一样的。进入DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(),这个方法之前的逻辑参考之前写的<spring源码分析之架构和Refresh>帖子.这个方法里面循环遍历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().这里需要注意下解析<dubbo:service interface="xxx.xxx" ref="xxxid"/>标签的ServiceBean类.普通的<bean>标签由spring来处理,和dubbo没关系.ServiceBean会把xml中ref引用的bean name,从ApplicationContext中取出bean的定义.把ref引用bean的完整路径设置为ServiceBean的id和name,比如xxx.DemoService.这个ServiceBean作为独立的bean放到beanDefinitionMap中.


(二)导出service

导出service的调用栈如下图所示:


1.在ServiceBean#setApplicationContext()里面把Spring里面的ApplicationContext设置到Dubbo的SpringExtensionFactory#contexts成员属性里面.然后调用AbstractApplicationContext#addApplicationListener把dubbo设置为spring的观察者.
2.真正从spring调用到dubbo导出服务的接口的是进入到ServiceBean#afterPropertiesSet回调里面.这个是spring创建dubbo的接口的bean,比如DemoService.调用getBean()时,传入的beanName是前面获取的<dubbo:service>的ref引用的完整路径.所有的ServiceBean填充完对象属性,开始做这个ServiceBean的初始化操作,回调ServiceBean#afterPropertiesSet()方法.
3.在ServiceBean#afterPropertiesSet()里面.把ApplicationConfig,RegistryConfig,ProtocolConfig设置到ServiceBean里面.
4.spring启动回调链路AbstractApplicationContext#refresh->AbstractApplicationContext#finishRefresh->SimpleApplicationEventMulticaster#doInvokeListener->com.alibaba.spring.context.OnceApplicationContextEventListener#onApplicationEvent->DubboBootstrapApplicationListener#onApplicationContextEvent->DubboBootstrap#start->ServiceConfig#export->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("<dubbo:service interface=\"\" /> 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);
        }
        //基本的是不是接口的检查.主要是防止在xml文件里面填一些不存在的配置项
        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.进入ServiceConfig#doExportUrls().dubbo可以配置接口导出到多个协议,针对每种协议,调用doExportUrlsFor1Protocol方法.

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

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

protected List<URL> loadRegistries(boolean provider) {
    checkRegistry();
    List<URL> registryList = new ArrayList<URL>();
    //遍历所有的注册中心配置
    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<String, String> map = new HashMap<String, String>();
                //添加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<URL> 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&timestamp=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<URL> registryURLs) {

    /* 省略部分代码,主要是读取配置,通过从上层导下层一次往map里面put,解决父子层级依赖关系问题.
    最后就生成 值为{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会在DubboExporter#delegateExporterMap的value中存储,key是url,消费者调用时通过这个map映射到这个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里面配置的<dubbo:protocol>内容,name是dubbo,map是前面读取的xml配置.

private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> 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接口,同一jvm进程导出的对象不适用代理,直接导出接口实现类的原对象.

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&timestamp=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&timestamp=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&registry=zookeeper&timestamp=1584018965180 .
代码如下:

public <T> Invoker<T> getInvoker(T proxy, Class<T> 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<T>(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<T> implements Invoker<T> {
	//接口的实现类
    private final T proxy;
    //接口的Class对象
    private final Class<T> type;
    //接口对应的注册中心url地址
    private final URL url;
    ...
}

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

public abstract class Wrapper {
	//Class对象到实际实现对象的映射
    private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, 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类使用arthas的jad反编译如下:

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 <T> Exporter<T> export(Invoker<T> 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 <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    /* 加载所有Filter接口的实现类,这里有EchoFilter,ClassLoaderFilter,GenericFilter,ContextFilter,TraceFilter,TimeoutFilter, MonitorFilter,ExceptionFilter八个*/
    List<Filter> 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<T> next = last;
            last = new Invoker<T>() {
            	...
            	//集中式职责链,依次调用
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }
                ...
            };
        }
    }
    return last;
}

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

public <T> Exporter<T> export(Invoker<T> 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<T>(protocol.export(invoker),
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
public class ListenerExporterWrapper<T> implements Exporter<T> {
	//实际创建的Exporter引用, 指向InjvmExporter.
    private final Exporter<T> exporter;

    private final List<ExporterListener> listeners;
 }

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

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

InjvmExporter继承自AbstractExporter。代码如下:

class InjvmExporter<T> extends AbstractExporter<T> {

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

    private volatile boolean unexported = false;
}

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

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

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

public <T> Exporter<T> export(final Invoker<T> 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&timestamp=1584018965207 
    导出,进入DubboProtocol#export(),导出dubbo协议的invoker,启动dubbo协议的本机的netty server等待连接.后面代码17处分析*/
    final ExporterChangeableWrapper<T> 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%26
    bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26
    qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222&timestamp=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<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}

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

public <T> Exporter<T> export(Invoker<T> 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<T> exporter = new DubboExporter<T>(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<T> extends AbstractExporter<T> {
	//字串为com.alibaba.dubbo.demo.DemoService:20880
    private final String key;
    //key是上面的key,value是DubboExporter对象本身.在这里做消费端调用过来时,url和接口实现类的映射,导出最核心对象.Exporter里面包含RegistryProtocol.InvokerDelegate->
    //DelegateProviderMetaDataInvoker->对象,
    private final Map<String, Exporter<?>> 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&timestamp=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<String> 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);
    }
}


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值