dubbo源码---服务暴露(3)

接着上一节,我们达到doExportForlProtocol()方法的第四段,我们组装好了URL,现在我们需要根据具体的协议,进行服务暴露了!

第一个是封装成Wrapper中,

一,本地服务暴露

exportLocal(url),位于ServiceConfig类中

private void exportLocal(URL url) {
    URL local = URLBuilder.from(url)
            .setProtocol(LOCAL_PROTOCOL)
            .setHost(LOCALHOST_VALUE)
            .setPort(0)
            .build();
    //创建invoker 并到处服务,protocol允许的时候,会调用injvmProtocol的export 【入】
    Exporter<?> exporter = PROTOCOL.export(
            PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));  //将[实例,接口,url],封装成url,然后进行暴露
    exporters.add(exporter);
}

1.1 封装成Invoker

  这个方法,我们调用的是ProxyFactory接口的实现类,先看一下顶层接口,

  有两种方法,一个是获得proxy代理对象,代理的是invoker,还有一个是封装成为invoker对象,注意这里还使用spi,扩展点。

@SPI("javassist")
public interface ProxyFactory {
    //create proxy.
    @Adaptive({PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
    //create proxy
    @Adaptive({PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
    //create proxy
    @Adaptive({PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}

  传入的三个参数依次:接口实现类,接口Class对象,URL    

  (默认是这个实现类):JavassistProxyFactory类: 工厂就是产生类的,产生的是Invoker类

public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        //创建 匿名invoker对象,并且实现doInvoke方法
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

    这里调用了getWrapper(),我们在上一节中,有详细的讲述,它是dubbo自己实现的代理方式,返回了一个wrapper。

自然的,同等级的JdkProxyFactory 自然是使用jdk的动态代理,可以看一下代码:

public class JdkProxyFactory extends AbstractProxyFactory {
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                Method method = proxy.getClass().getMethod(methodName, parameterTypes);
                return method.invoke(proxy, arguments);
            }
        };
    }
}

   他们两个代理工厂都创建了 匿名的invoker对象,并且实现了doInvoke方法,两者的实现方式不同,可以理解,现在终于找到了invoker是的本质了,它就是对三者信息的封装。

public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
    private final T proxy;
    private final Class<T> type;
    private final URL url;
...
}

1.2 export(invoker)

  来到InjvmProtocol类中 

    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }

  返回了一个暴露bean:InjvmExporter类,它是对一个暴露点的封装,使用serviceKey作为key,然后放入map中。key是这个类私有的,但是map是全部本地服务通用的!,存放在AbstractProtocol中

class InjvmExporter<T> extends AbstractExporter<T> {

    private final String key;
    private final Map<String, Exporter<?>> exporterMap;

    InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
        super(invoker);
        this.key = key;
        this.exporterMap = exporterMap;
        exporterMap.put(key, this);
    }
    @Override
    public void unexport() {
        super.unexport();
        exporterMap.remove(key);
    }
}

最后,将export添加到链表中,本地服务暴露结束。这里没有涉及到网络传输。

private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>(); //The exported services

 

二,导出服务到远程

RegistryProtocol类的export()方法

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    URL registryUrl = getRegistryUrl(originInvoker);

    URL providerUrl = getProviderUrl(originInvoker);

    final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); //监听初始化

    providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
    //export invoker 【入】,导出服务 ★ 所谓到处就是,使用netty暴露服务,启动服务器;  所谓注册就是把信息放到zk上面,便于其他服务发现!
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);

    // 注册 url
    final Registry registry = getRegistry(originInvoker);
    final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);

    // 是否延迟 发布
    boolean register = providerUrl.getParameter(REGISTER_KEY, true);
    //--------- 注册服务 ★------------ 服务注册不是必须的,可以直连!
    if (register) {
        register(registryUrl, registeredProviderUrl);
    }


    registerStatedUrl(registryUrl, registeredProviderUrl, register);
    //------  订阅override 数据 -------------------
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);

    exporter.setRegisterUrl(registeredProviderUrl);
    exporter.setSubscribeUrl(overrideSubscribeUrl);

    notifyExport(exporter);

    return new DestroyableExporter<>(exporter);
}

进入:

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
    String key = getCacheKey(originInvoker);
    //访问 缓冲
    return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
        Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
        return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);  //如果配置协议为dubbo,这里就会调用dubboProtocol中的export()
    });
}

DubboProtocol类的export()

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    URL url = invoker.getUrl();
    // export service. 获取服务坐标
    String key = serviceKey(url);
    //创建 DubboExporter
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);
    //本地存根
    //export an stub service for dispatching event
    Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
        String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
        }
    }
    // 启动服务器 ★
    openServer(url);
    optimizeSerialization(url);

    return exporter;
}

启动服务器:

private void openServer(URL url) {
    // 获取 host:port
    String key = url.getAddress();
    //client can export a service which's only for server to invoke
    boolean isServer = url.getParameter(IS_SERVER_KEY, true);
    if (isServer) {
        //访问缓冲
        ProtocolServer server = serverMap.get(key);
        if (server == null) {
            synchronized (this) {
                server = serverMap.get(key);
                if (server == null) {
                    //创建 服务器实例
                    serverMap.put(key, createServer(url)); //【入】
                }
            }
        } else {
            //服务器已经创建,重置服务器
            server.reset(url);
        }
    }
}

创建服务实例:

private ProtocolServer createServer(URL url) {
    url = URLBuilder.from(url)
            // send readonly event when server closes, it's enabled by default
            .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
            // 添加心跳检测到 url中
            .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
            .addParameter(CODEC_KEY, DubboCodec.NAME)
            .build();
    //获取server参数,默认为netty
    String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
    //通过spir检测是否存在server参数所代表的 ransporter扩展,不存在则抛出异常
    if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
        throw new RpcException("Unsupported server type: " + str + ", url: " + url);
    }

    ExchangeServer server;
    try {
        //创建ExhangeServer ★【入】
        server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
        throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
//获取 Client参数,可指定netty,mina
    str = url.getParameter(CLIENT_KEY);
    if (str != null && str.length() > 0) {
        //获取所有的transporter实现类名称集合,
        Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
        // 检测当前 Dubbo 所支持的 Transporter 实现类名称列表中,
        // 是否包含 client 所表示的 Transporter,若不包含,则抛出异常
        if (!supportedTypes.contains(str)) {
            throw new RpcException("Unsupported client type: " + str);
        }
    }

    return new DubboProtocolServer(server);
}

绑定入口:

public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handler == null) {
        throw new IllegalArgumentException("handler == null");
    }
    url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
    //获取Exchanger 默认为 HeaderExchanger
    //紧接着调用HeaderExchanger的Bind方法创建ExchangeServer实例
    return getExchanger(url).bind(url, handler);  //b【入】HeaderExchanger
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值