dubbo实现简析(2)

接上文,看export()的代码:
checkInterfaceAndMethods(interfaceClass, methods);
            checkRef();
checkApplication();
        checkRegistry();
        checkProtocol();
checkStubAndMock(interfaceClass);
//上面都是各种check,看各种参数和属性是否合法,不合法抛出相应异常。
doExportUrls(); //但是核心调用在这里

private void doExportUrls() {
        List<URL> registryURLs = loadRegistries(true);  // 所有的注册中心地址列表
        for (ProtocolConfig protocolConfig : protocols) { //所有的协议, 每种协议都做一次暴露,比如dubbo,hessian协议
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }
这个registryURL到底是怎么样的呢,这里给出一个例子:
dubbo://10.224.195.115:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.4.1&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello & monitor= dubbo%3A%2F%2F224.5.6.7%3A1234%2Fcom.alibaba.dubbo.registry.RegistryService%3Fapplication%3Ddemo-consumer%26dubbo%3D2.4.1%26pid%3D22843%26protocol%3Dregistry%26refer%3Ddubbo%253D2.4.1%2526interface%253Dcom.alibaba.dubbo.monitor.MonitorService%2526pid%253D22843%2526timestamp%253D1370658576603%26registry%3Dmulticast%26timestamp%3D1370658576595&pid=22843&revision=2.4.1&side=consumer&timestamp=1370658576524

简单说明:
名为 com.alibaba.dubbo.demo.DemoService的服务以dubbo协议在 10.224.195.115:20880这个地址提供服务,提供的接口方法是sayHello(),并且在这个例子中,Provider和consumer是以广播地址互相发现的,实际使用可能是将服务注册到Redis中心或者Zookeeper中心。

继续看代码:如果scope属性设为local,就暴露为本地服务;又如果protocol=injvm,那就在同一个jvm内,啥都不用做了,如果不是则需要做处理:
Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);

如果scope=remote,则暴露为远程服务:
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
Exporter<?> exporter = protocol.export(invoker);
exporters.add(exporter);

基本的过程是一样的: 1 先调用proxyFactory.getInvoker()生成Invoker对象  2 调用相对应协议的export方法,真正地把服务暴露出去。

因此这个Invoker接口和实现,可以说是dubbo的核心。它连接了生产者和消费者。生产者将interfaceClass这个ServiceBean转为一个Invoker(调用代理),并暴露这个invoker;  通过远程协议消费者会拿到这个Invoker,将它转回成 interfaceClass 这个Bean的代理 ,这样消费者就可以调用Proxy 的服务方法了。

下面我们重点分析 proxyFactory.getInvoker()和    protocol.export(invoker); 俩个方法的实现。
public class JdkProxyFactory extends AbstractProxyFactory  {

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
    }

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

}


public <T> Exporter<T> export(final Invoker<T> invoker) throws RpcException {
        final String uri = serviceKey(invoker.getUrl());
        Exporter<T> exporter = (Exporter<T>) exporterMap.get(uri);
        if (exporter != null) {
          return exporter;
        }
        final Runnable runnable = doExport(proxyFactory.getProxy(invoker), invoker.getInterface(), invoker.getUrl());
        exporter = new AbstractExporter<T>(invoker) {
            public void unexport() {
                super.unexport();
                exporterMap.remove(uri);
                if (runnable != null) {
                    try {
                        runnable.run();
                    } catch (Throwable t) {
                        logger.warn(t.getMessage(), t);
                    }
                }
            }
        };
        exporterMap.put(uri, exporter);
        return exporter;
    }
public abstract class AbstractProxyFactory implements ProxyFactory {

    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
        Class<?>[] interfaces = null;
        String config = invoker.getUrl().getParameter("interfaces");
        if (config != null && config.length() > 0) {
            String[] types = Constants.COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                interfaces = new Class<?>[types.length + 2];
                interfaces[0] = invoker.getInterface();
                interfaces[1] = EchoService.class;
                for (int i = 0; i < types.length; i ++) {
                    interfaces[i + 1] = ReflectUtils.forName(types[i]);
                }
            }
        }
        if (interfaces == null) {
            interfaces = new Class<?>[] {invoker.getInterface(), EchoService.class};
        }
        return getProxy(invoker, interfaces);
    }
    
    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);

}
从以上代码,我们看到doExport方法的第一个参数实际上是个jdk动态代理。这个proxy被调用方法时,会触动 InvokerInvocationHandler.invoke(), 我们来看看这个invoke方法;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   ......
   return invoker.invoke(new RpcInvocation(method, args)).recreate();//返回RpcResult.result ,也就是方法调用的最终结果。
}

public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
      public Result invoke(Invocation invocation) throws RpcException {
        try {
            return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));   //哈哈  这里终于看到上文定义的回调函数doinvoke了。
        } catch (InvocationTargetException e) {
            return new RpcResult(e.getTargetException());
        } catch (Throwable e) {
            throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }
}

protected <T> Runnable doExport(final T impl, Class<T> type, URL url) throws RpcException {
        final RmiServiceExporter rmiServiceExporter = new RmiServiceExporter();
        rmiServiceExporter.setRegistryPort(url.getPort());
        rmiServiceExporter.setServiceName(url.getPath());
        rmiServiceExporter.setServiceInterface(type);
        rmiServiceExporter.setService(impl);
        try {
            rmiServiceExporter.afterPropertiesSet();
        } catch (RemoteException e) {
            throw new RpcException(e.getMessage(), e);
        }
        return new Runnable() {
            public void run() {
                try {
                    rmiServiceExporter.destroy();
                } catch (Throwable e) {
                    logger.warn(e.getMessage(), e);
                }
            }
        };
    }
以RMI协议为例, 它是调用了spring中现成的RmiServiceExporter类将服务暴露出去的;如果是自定义的dubbo协议,则需要自行实现整个暴露服务的过程。后面会介绍dubbo协议的实现。

从上面代码再次看到,Invoker对象的重要性。下次我们讲讲ReferenceBean的处理过程。

转载于:https://my.oschina.net/u/603187/blog/552065

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值