码迷,mamicode.com
首页 > 其他好文 > 详细

Dubbo源码阅读笔记4

时间:2018-03-19 19:09:07      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:不能   oid   tin   获取   hand   type   super   协议   xtend   

### 发布服务到本地

发布本地服务的代码在ServiceConfig.doExportUrlsFor1Protocol方法里
主要代码如下

// 通过动态代理工厂生成实现类调用器Invoker, Invoker相当于动态代理类
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

// 只是将代理和配置放到一起
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

// 发布服务到协议中,现在是InjvmProtocol
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);

默认用的动态代理工厂是JavassistProxyFactory
通过AbstractProxyInvoker类封装成Invoker
Wrapper是通过字节码技术给类增加了几个增强方法
想查看javassist生成的class源代码可以通过CtClass类的writeFile方法输出到本地文件,再反编译

// JavassistProxyFactory.java
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    // TODO Wrapper类不能正确处理带$的类名
    final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(‘$‘) < 0 ? proxy.getClass() : type);
    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);
        }
    };
}

JdkProxyFactory则是直接用反射调用

// JdkProxyFactory.java
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发布
用的协议是InjvmProtocol
injvm协议非常简单,不用监听端口什么的,直接返回InjvmExporter实例
到这里发布服务到本地已经完成了

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

// InjvmExporter.java
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);
    }

    public void unexport() {
        super.unexport();
        exporterMap.remove(key);
    }
}

### 调用本地服务

服务引用在初始化时生成目标接口的代理实现
在ReferenceConfig.createProxy方法生成

// ReferenceConfig.java
if (isJvmRefer) {
    URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
    
    // 通过服务协议获取服务调用器, refprotocol和发布时的protocol是同一实例
    invoker = refprotocol.refer(interfaceClass, url);
    if (logger.isInfoEnabled()) {
        logger.info("Using injvm service " + interfaceClass.getName());
    }
}

// InjvmProtocol.java
public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException {
    // exporterMap保存了已发布的服务,因为发布和引用都用的同一个protocol实例,所以exporterMap也是同一个。
    return new InjvmInvoker<T>(serviceType, url, url.getServiceKey(), exporterMap);
}

创建动态代理返回
默认用的动态代理工厂是JavassistProxyFactory,用字节码技术生成目标接口的代理类
如果使用JdkProxyFactory,则没有字节码生成类的步骤,直接动态代理调用Invoker类的invoke方法

// ReferenceConfig.java
// 创建服务代理
return (T) proxyFactory.getProxy(invoker);

// JavassistProxyFactory.java
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

// JdkProxyFactory.java
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvokerInvocationHandler(invoker));
}

// 重点**
// javassist生成的类继承自Proxy,并实现了目标接口,目标方法会被实现一次,handler是上面的InvokerInvocationHandler实例
// 以下是生成的方法
public String sayHello(String $1) {
    Object[] args = new Object[1]; 
    args[0] = ($w)$1; 
    Object ret = handler.invoke(this, methods[0], args); 
    return (java.lang.String)ret;
}

// InvokerInvocationHandler.java
// 该类实现了InvocationHandler,目的是支持jdk动态代理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    Class<?>[] parameterTypes = method.getParameterTypes();
    if (method.getDeclaringClass() == Object.class) {
        return method.invoke(invoker, args);
    }
    if ("toString".equals(methodName) && parameterTypes.length == 0) {
        return invoker.toString();
    }
    if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
        return invoker.hashCode();
    }
    if ("equals".equals(methodName) && parameterTypes.length == 1) {
        return invoker.equals(args[0]);
    }
    return invoker.invoke(new RpcInvocation(method, args)).recreate();
}

最后在调用目标方法的时候,通过调用方invoker找到服务方invoker

// InjvmInvoker.java
// 此时在调用方invoker实例
public Result doInvoke(Invocation invocation) throws Throwable {
    // 通过exporterMap找到服务方exporter
    Exporter<?> exporter = InjvmProtocol.getExporter(exporterMap, getUrl());
    if (exporter == null) {
        throw new RpcException("Service [" + key + "] not found.");
    }
    RpcContext.getContext().setRemoteAddress(NetUtils.LOCALHOST, 0);
    // 拿出服务方invoker并调用方法
    return exporter.getInvoker().invoke(invocation);
}

Dubbo源码阅读笔记4

标签:不能   oid   tin   获取   hand   type   super   协议   xtend   

原文地址:https://www.cnblogs.com/amwyyyy/p/8603830.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!