Dubbo源码解析(三)执行器 Invoker

Invoker

在dubbo中,万物皆是Invoker,即便是Exporter也是由Invoker进化而成的

那么Invoker到底是什么鬼

在 Dubbo 的核心领域模型中:

Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。

Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。

继续看一下类图
Dubbo源码解析(三)执行器 Invoker_第1张图片

Dubbo协议下的执行流程图

Dubbo源码解析(三)执行器 Invoker_第2张图片

主要分析一下DubboInvoker的源码

public interface Invoker extends Node {

    /**
     * get service interface.
     *
     * @return service interface.
     */
    Class getInterface();

    /**
     * invoke.
     *
     * @param invocation
     * @return result
     * @throws RpcException
     */
    Result invoke(Invocation invocation) throws RpcException;

}
public abstract class AbstractInvoker implements Invoker {

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private final Class type;

    private final URL url;

    private final Map attachment;

    private volatile boolean available = true;

    private AtomicBoolean destroyed = new AtomicBoolean(false);

    public AbstractInvoker(Class type, URL url) {
        this(type, url, (Map) null);
    }

    public AbstractInvoker(Class type, URL url, String[] keys) {
        this(type, url, convertAttachment(url, keys));
    }

    public AbstractInvoker(Class type, URL url, Map attachment) {
        if (type == null)
            throw new IllegalArgumentException("service type == null");
        if (url == null)
            throw new IllegalArgumentException("service url == null");
        this.type = type;
        this.url = url;
        this.attachment = attachment == null ? null : Collections.unmodifiableMap(attachment);
    }

    private static Map convertAttachment(URL url, String[] keys) {
        if (keys == null || keys.length == 0) {
            return null;
        }
        Map attachment = new HashMap();
        for (String key : keys) {
            String value = url.getParameter(key);
            if (value != null && value.length() > 0) {
                attachment.put(key, value);
            }
        }
        return attachment;
    }

    public Class getInterface() {
        return type;
    }

    public URL getUrl() {
        return url;
    }

    public boolean isAvailable() {
        return available;
    }

    protected void setAvailable(boolean available) {
        this.available = available;
    }

    public void destroy() {
        if (!destroyed.compareAndSet(false, true)) {
            return;
        }
        setAvailable(false);
    }

    public boolean isDestroyed() {
        return destroyed.get();
    }

    public String toString() {
        return getInterface() + " -> " + (getUrl() == null ? "" : getUrl().toString());
    }

    public Result invoke(Invocation inv) throws RpcException {
        if (destroyed.get()) {
            throw new RpcException("Rpc invoker for service " + this + " on consumer " + NetUtils.getLocalHost()
                    + " use dubbo version " + Version.getVersion()
                    + " is DESTROYED, can not be invoked any more!");
        }
        RpcInvocation invocation = (RpcInvocation) inv;
        invocation.setInvoker(this);
        if (attachment != null && attachment.size() > 0) {
            invocation.addAttachmentsIfAbsent(attachment);
        }
        Map context = RpcContext.getContext().getAttachments();
        if (context != null) {
            invocation.addAttachmentsIfAbsent(context);
        }
        if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
            invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
        }
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);


        try {
            // 调用逻辑
            return doInvoke(invocation);
        } catch (InvocationTargetException e) { // 包装各种异常 biz exception
            Throwable te = e.getTargetException();
            if (te == null) {
                return new RpcResult(e);
            } else {
                if (te instanceof RpcException) {
                    ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
                }
                return new RpcResult(te);
            }
        } catch (RpcException e) {
            if (e.isBiz()) {
                return new RpcResult(e);
            } else {
                throw e;
            }
        } catch (Throwable e) {
            return new RpcResult(e);
        }
    }

    protected abstract Result doInvoke(Invocation invocation) throws Throwable;

}
public class DubboInvoker<T> extends AbstractInvoker<T> {

    private final ExchangeClient[] clients;

    private final AtomicPositiveInteger index = new AtomicPositiveInteger();

    private final String version;

    private final ReentrantLock destroyLock = new ReentrantLock();

    private final Set> invokers;

    public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients) {
        this(serviceType, url, clients, null);
    }


    /**
     *  构造方法
     */
    public DubboInvoker(Class serviceType, URL url, ExchangeClient[] clients, Set> invokers) {
        super(serviceType, url, new String[]{Constants.INTERFACE_KEY, Constants.GROUP_KEY, Constants.TOKEN_KEY, Constants.TIMEOUT_KEY});
        this.clients = clients;
        // get version.
        this.version = url.getParameter(Constants.VERSION_KEY, "0.0.0");
        this.invokers = invokers;
    }

    /**
     * 真正的远程调用逻辑
     */
    @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
        final String methodName = RpcUtils.getMethodName(invocation);
        inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
        inv.setAttachment(Constants.VERSION_KEY, version);

        // 传输端的客户端
        ExchangeClient currentClient;
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
            // 是否异步
            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
            // 是否返回值,也就是相当于发送了一个指令,不在乎服务端的返回
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
            int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
            if (isOneway) { // 无论同步、异步,只发送指令
                // sent="true" 等待消息发出,消息发送失败将抛出异常。
                // sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。
                boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                // 客户端发送请求
                currentClient.send(inv, isSent);

                RpcContext.getContext().setFuture(null);
                return new RpcResult();
            } else if (isAsync) { // 异步调用
                // 发送请求,并返回future
                ResponseFuture future = currentClient.request(inv, timeout);
                // 设置future
                RpcContext.getContext().setFuture(new FutureAdapter(future));
                return new RpcResult();
            } else { // 同步串行化调用
                //
                RpcContext.getContext().setFuture(null);
                // 发送请求,并返回响应
                return (Result) currentClient.request(inv, timeout).get();
            }
        } catch (TimeoutException e) {
            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } catch (RemotingException e) {
            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

    @Override
    public boolean isAvailable() {
        if (!super.isAvailable())
            return false;
        for (ExchangeClient client : clients) {
            if (client.isConnected() && !client.hasAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY)) {
                //cannot write == not Available ?
                return true;
            }
        }
        return false;
    }

    public void destroy() {
        // in order to avoid closing a client multiple times, a counter is used in case of connection per jvm, every
        // time when client.close() is called, counter counts down once, and when counter reaches zero, client will be
        // closed.
        if (super.isDestroyed()) {
            return;
        } else {
            // double check to avoid dup close
            destroyLock.lock();
            try {
                if (super.isDestroyed()) {
                    return;
                }
                super.destroy();
                if (invokers != null) {
                    invokers.remove(this);
                }
                for (ExchangeClient client : clients) {
                    try {
                        client.close(ConfigUtils.getServerShutdownTimeout());
                    } catch (Throwable t) {
                        logger.warn(t.getMessage(), t);
                    }
                }

            } finally {
                destroyLock.unlock();
            }
        }
    }
} 
  

看完这个逻辑,就能理解这句话了

而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,
Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,
Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,
它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。

因为实现RMI,不再需要通过remoting传输消息层了,因为 Remoting 实现是 Dubbo 协议的实现,RMI有自己的传输机制和方法调用机制,
详细看RmiProtocol

    protected  T doRefer(final Class serviceType, final URL url) throws RpcException {
        final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean();
        // RMI needs extra parameter since it uses customized remote invocation object
        if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getVersion()).equals(Version.getVersion())) {
            // Check dubbo version on provider, this feature only support
            rmiProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() {
                public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) {
                    // 执行器
                    return new RmiRemoteInvocation(methodInvocation);
                }
            });
        }
        rmiProxyFactoryBean.setServiceUrl(url.toIdentityString());
        rmiProxyFactoryBean.setServiceInterface(serviceType);
        rmiProxyFactoryBean.setCacheStub(true);
        rmiProxyFactoryBean.setLookupStubOnStartup(true);
        rmiProxyFactoryBean.setRefreshStubOnConnectFailure(true);
        rmiProxyFactoryBean.afterPropertiesSet();
        return (T) rmiProxyFactoryBean.getObject();
    }

com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation

@Override
    public Object invoke(Object targetObject) throws NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        RpcContext context = RpcContext.getContext();
        context.setAttachments((Map) getAttribute(dubboAttachmentsAttrName));
        try {
            return super.invoke(targetObject);
        } finally {
            context.setAttachments(null);
        }
    }

org.springframework.remoting.support.RemoteInvocation

    /**
     * Perform this invocation on the given target object.
     * Typically called when a RemoteInvocation is received on the server.
     * @param targetObject the target object to apply the invocation to
     * @return the invocation result
     * @throws NoSuchMethodException if the method name could not be resolved
     * @throws IllegalAccessException if the method could not be accessed
     * @throws InvocationTargetException if the method invocation resulted in an exception
     * @see java.lang.reflect.Method#invoke
     */
    public Object invoke(Object targetObject)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {

        Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes);
        return method.invoke(targetObject, this.arguments);
    }

直接通过java的反射执行,因为spring已经实现了RMI,即已经把这些事情做了。

看下来就发现了真正和Invoker绑定在一起的就是Protocol的doExport和doRefer这两个方法,而Invoker无非就是一个类,或者说一种作用域,有了它,很多事情都方便了,在固定的层次上做固定的事情。
回顾一下接口

   /Invoker/
   /**
     * get service interface.
     *
     * @return service interface.
     */
    Class getInterface();

    /**
     * invoke.
     *
     * @param invocation
     * @return result
     * @throws RpcException
     */
    Result invoke(Invocation invocation) throws RpcException;

    / Node ///

     /**
     * get url.
     *
     * @return url.
     */
    URL getUrl();

    /**
     * is available.
     *
     * @return available.
     */
    boolean isAvailable();

    /**
     * destroy.
     */
    void destroy();

你可能感兴趣的:(dubbo,Dubbo,源码解析)