Dubbo源码学习--服务发布(ProxyFactoryInvoker)

Posted 清明上河图

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo源码学习--服务发布(ProxyFactoryInvoker)相关的知识,希望对你有一定的参考价值。

上文分析了Dubbo服务发布的整体流程,但服务代理生成的具体细节介绍得还不是很详细。下面将会接着上文继续分析。上文介绍了服务代理生成的切入点,如下:

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

这里的proxyFactory是在ServiceConfig中定义的,是final类型静态变量,赋值后无法进行修改。如下:

    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

proxyFactory通过ExtensionLoader拓展机制进行加载。查看ProxyFactory接口源码如下:

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

@SPI("javassist")
public interface ProxyFactory {

    /**
     * create proxy.
     *
     * @param invoker
     * @return proxy
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    /**
     * create invoker.
     *
     * @param <T>
     * @param proxy
     * @param type
     * @param url
     * @return invoker
     */
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

ProxyFactory接口有三个实现类,分别为JavassistProxyFactory、JdkProxyFactory、StubProxyFactoryWrapper。其中JavassistProxyFactory、JdkProxyFactory作为代理工厂,StubProxyFactoryWrapper实现了对代理工厂进行装饰的功能。在Dubbo中通过SPI配置默认的代理工厂为JavassistProxyFactory(具体是如何实现配置的,这里就不讲了,详见Dubbo SPI拓展机制)。

下面来重点看看JavassistProxyFactory代理工厂。

JavassistProxyFactory继承实现关系图如下:
技术分享图片

JavassistProxyFactory源码非常简单,只有两个方法:

package com.alibaba.dubbo.rpc.proxy.javassist;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.bytecode.Proxy;
import com.alibaba.dubbo.common.bytecode.Wrapper;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.proxy.AbstractProxyFactory;
import com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker;
import com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler;

public class JavassistProxyFactory extends AbstractProxyFactory {

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

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

其中getProxy是实现抽象类AbstractProxyFactory中的抽象方法。AbstractProxyFactory抽象类实现了ProxyFactory接口中getProxy方法,JdkProxyFactory也实现了抽象类AbstractProxyFactory中的getProxy抽象方法。Javassist与Jdk动态代理的共同部分被封装在父类AbstractProxyFactory中,具体的实现类只需负责实现代理生成过程的差异化部分。

其中getInvoker方法是在ProxyFactory接口中定义的,用于创建Invoker。getInvoker中代码很简单,直接返回一个匿名类。匿名类继承了AbstractProxyInvoker抽象类,AbstractProxyInvoker抽象类又实现了Invoker接口,即表明改匿名类实现了Invoker接口,匿名类是封装了服务提供者的调用者。

Invoker接口定义了一个泛型。定义的方法很简单,只有两个方法,如下:

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.Node;

public interface Invoker<T> extends Node {

    //获取服务对象接口
    Class<T> getInterface();

    //获取封装了服务的调用者
    Result invoke(Invocation invocation) throws RpcException;
}

抽象类AbstractProxyInvoker实现了Invoker接口,AbstractProxyInvoker定义属性和构造方法如下:

    private final T proxy;

    private final Class<T> type;

    private final URL url;

    public AbstractProxyInvoker(T proxy, Class<T> type, URL url) {
        if (proxy == null) {
            throw new IllegalArgumentException("proxy == null");
        }
        if (type == null) {
            throw new IllegalArgumentException("interface == null");
        }
        if (!type.isInstance(proxy)) {
            throw new IllegalArgumentException(proxy.getClass().getName() + " not implement interface " + type);
        }
        this.proxy = proxy;
        this.type = type;
        this.url = url;
    }
  • proxy:是final类型变量,指向服务提供者
  • type:是final类型变量,服务的接口类型
  • url:是final类型变量,携带服务地址、端口等多种信息的自定义URL对象

构造方法主要对输入参数做一些校验,然后将输入参数值直接赋值给定义属性,赋值后定义属性值将不可更改。

AbstractProxyInvoker也实现了invoker方法。方法内部很简单,直接通过RpcResult创建一个对象即可,创建RpcResult时的构建参数是通过方法doInvoke生成的。如下:

    public Result invoke(Invocation invocation) throws RpcException {
        try {
            return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
        } 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);
        }
    }

这里的doInvoke方法是抽象方法,由子类实现。抽象方法定义如下:

    protected abstract Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable;

在ProxyFactory接口JavassistProxyFactory实现类中,getInvoker方法内部通过匿名内部类实现了doInvoke抽象方法。

Result接口主要定义了RPC 调用的相关方法,如下:

package com.alibaba.dubbo.rpc;

import java.util.Map;

public interface Result {

    Object getValue();

    Throwable getException();

    boolean hasException();

    Object recreate() throws Throwable;

    @Deprecated
    Object getResult();

    Map<String, String> getAttachments();

    String getAttachment(String key);

    String getAttachment(String key, String defaultValue);

}

RpcResult是对Result接口的一个实现。可看作对传入对象Object的一个包装,部分源码如下:

public class RpcResult implements Result, Serializable {

    private static final long serialVersionUID = -6925924956850004727L;

    private Object result;

    private Throwable exception;

    private Map<String, String> attachments = new HashMap<String, String>();

    public RpcResult() {
    }

    public RpcResult(Object result) {
        this.result = result;
    }

    public RpcResult(Throwable exception) {
        this.exception = exception;
    }

    public Object recreate() throws Throwable {
        if (exception != null) {
            throw exception;
        }
        return result;
    }
}

本节介绍了Dubbo服务发布的Invoker生成过程,下节将继续分析Dubbo服务发布的服务暴露过程


以上是关于Dubbo源码学习--服务发布(ProxyFactoryInvoker)的主要内容,如果未能解决你的问题,请参考以下文章

dubbo源码学习dubbo暴露服务的过程

dubbo源码学习一:基础知识及使用的相关技术

dubbo学习-服务暴露与注册源码剖析

dubbo源码学习:暴露服务的过程

Dubbo源码学习(三服务暴露ServiceBean)

Dubbo源码学习(三服务暴露ServiceBean)