一、服务引用

1、初始的时候,是在spring容器初始化的时候,即要生成引用的代理类。
ReferenceBean implements InitializingBean //实现了InitializingBean,在容器初始化的时候就会执行
  --ReferenceBean.afterPropertiesSet()
   --ReferenceBean.getObject()//获取
    --ReferenceConfig.get() 
     --ReferenceConfig.init()//init 方法主要用于处理配置,以及调用 createProxy 生成代理类
2、生成目标类的代理类,用于远程调用
ReferenceConfig.init() 
 --//刚一上来和ServiceConfig中一致,需要检查对应的配置是否完善,配置是否可用
 --//之后,调用createProxy(map)//生成代理类,map中有对应的配置信息
 --ReferenceConfig.createProxy()
  --//1.判断是不是本地引用 
        final boolean isJvmRefer;
        if (isInjvm() == null) {
            // url被指定,直连,不做本地引用
            if (url != null && url.length() > 0) { // if a url is specified, don't do local reference
                isJvmRefer = false;
                // 根据 url 的协议、scope 以及 injvm 等参数检测是否需要本地引用
                // 比如如果用户显式配置了 scope=local,此时 isInjvmRefer 返回 true
            } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
                // by default, reference local service if there is
                isJvmRefer = true;
            } else {
                isJvmRefer = false;
            }
        } else {
            isJvmRefer = isInjvm().booleanValue();
        }
  --//2.如果是本地引用,生成对应的injvm协议的url,并生成对应的invoker对应
        // 生成本地引用 URL,协议为 injvm
        URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
        // 调用 refer 方法构建 InjvmInvoker 实例
        invoker = refprotocol.refer(interfaceClass, url);    
  --//3.如果设置了url,表示想要直连生产者
        String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);//切割url,得到直连url
        if (us != null && us.length > 0) {
            for (String u : us) {
                URL url = URL.valueOf(u);
                if (url.getPath() == null || url.getPath().length() == 0) {
                    // 设置接口全限定名为 url 路径
                    url = url.setPath(interfaceName);
                }
                // 检测 url 协议是否为 registry,若是,表明用户想使用指定的注册中心
                if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                    // 将 map 转换为查询字符串,并作为 refer 参数的值添加到 url 中
                    urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
                } else {
                    // 合并 url,移除服务提供者的一些配置(这些配置来源于用户配置的 url 属性),
                    // 比如线程池相关配置。并保留服务提供者的部分配置,比如版本,group,时间戳等
                    // 最后将合并后的配置设置为 url 查询字符串中。
                    urls.add(ClusterUtils.mergeUrl(url, map));
                }
            }
        } 
  --//4.需要用到注册中心,从注册中心的配置中组装URL
    List<URL> us = loadRegistries(false);
    if (us != null && !us.isEmpty()) {
        for (URL u : us) {
            URL monitorUrl = loadMonitor(u);
            if (monitorUrl != null) {
                map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
            }
            // 添加 refer 参数到 url 中,并将 url 添加到 urls 中
            urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
        }
    }  
    
  --//5.根据配置url,判断是单注册中心还是多注册中心,或者是多服务提供者,生成对应的Invoker
       if (urls.size() == 1) {
            //这个地方的protocol 如果是用户自己想直连的话,没有设置url的协议,默认生成的是dubboProtocol
            invoker = refprotocol.refer(interfaceClass, urls.get(0));
              --DubboInvoker.refer()//直接返回DubboInvoker
                --DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        } else {
            // 多个注册中心或多个服务提供者,或者两者混合
            List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
            URL registryURL = null;
            // 获取所有的 Invoker
            for (URL url : urls) {
                // 通过 refprotocol 调用 refer 构建 Invoker,refprotocol 会在运行时
                // 根据 url 协议头加载指定的 Protocol 实例,并调用实例的 refer 方法
                invokers.add(refprotocol.refer(interfaceClass, url));
                  --//通过RegistryProtocol.refer获取Invoker对象
                   --RegistryProtocol.doRefer()
                     --Invoker invoker = cluster.join(directory);//加载directory,生成MockClusterInvoker这个是个包装类,会包装默认的FailoverCluster
                        ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
                        return invoker; //返回     MockClusterInvoker          
                if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                    registryURL = url; // use last registry url
                }
            }
            if (registryURL != null) { // registry url is available
                // use AvailableCluster only when register's cluster is available
                //如果注册中心链接不为空,则将使用 AvailableCluster
                URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
                // 创建 StaticDirectory 实例,并由 Cluster 对多个 Invoker 进行合并
                invoker = cluster.join(new StaticDirectory(u, invokers));
            } else { // not a registry url
                invoker = cluster.join(new StaticDirectory(invokers));
            }
        }     
        
     --//6.根据返回的Invoker生成代理里Proxy0
       proxyFactory.getProxy(invoker);
         --StubProxyFactoryWrapper.getProxy();
           --AbstractProxyFactory.getProxy();
             -- interfaces[0] = invoker.getInterface();//向代理类中注入两个接口,一个时目标接口,一个是EchoServic回声测试
                interfaces[1] = EchoService.class;
           --JavassistProxyFactory.getProxy(invoker,interfaces);//得到代理类
3.生成的代理类
public class proxy0
        implements ClassGenerator.DC,
        EchoService,
        DemoService {

    public static Method[] methods;
    private InvocationHandler handler;

    @Override
    public String sayHello(String string) {
        // 将参数存储到 Object 数组中
        Object[] arrobject = new Object[]{string};
        Object object = null;
        try {
            // 调用 InvocationHandler 实现类的 invoke 方法进行远程调用得到调用结果
            object = this.handler.invoke(this, methods[0], arrobject);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 返回调用结果
        return (String) object;
    }

    /** 回声测试方法 */
    @Override
    public Object $echo(Object object) {
        Object[] arrobject = new Object[]{object};
        Object object2 = null;
        try {
            object2 = this.handler.invoke(this, methods[1], arrobject);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return object2;
    }

    public proxy0() {
    }

    public proxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }
}