Registro de aprendizaje de Dubbo (21) - Llamada de servicio [7] - Suplemento de Dubbo

Dubbo agregado

Mecanismo asíncrono a síncrono

1. Ejecución del cliente: AsyncToSyncInvoker#invoke

Después de ejecutar invocar#invocar, se devuelve una instancia de Result y se llama al método asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS) para bloquear infinitamente mientras se espera que se devuelva el resultado de la respuesta;

public class AsyncToSyncInvoker<T> implements Invoker<T> {
    
    

    private Invoker<T> invoker;

    public AsyncToSyncInvoker(Invoker<T> invoker) {
    
    
        this.invoker = invoker;
    }
    @Override
    public Result invoke(Invocation invocation) throws RpcException {
    
    
        // 异步转同步

        Result asyncResult = invoker.invoke(invocation);  // AsyncRpcResult--->CompletableFuture

        try {
    
    
            // 如果invocation指定是同步的,则阻塞等待结果
            if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) {
    
    
                asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
            }
        } catch (InterruptedException e) {
    
    
        
        } catch (Throwable e) {
    
    
            throw new RpcException(e.getMessage(), e);
        }
        return asyncResult;
    }

Aquí Future está representado por AsyncToSyncInvoker#asyncResult;

2. Ejecución del cliente: DubboInvoker#invoke

  • Cree una instancia de AsyncRpcResult asyncRpcResult;
  • Llame al cliente para enviar datos, devuelva la respuesta de la instancia CompleteFutureFuture;
  • asyncRpcResult.subscribeTo(responseFuture), cuando se complete responseFuture, se notificará asyncRpcResult;
  • devolver asyncRpcResult;

Es decir, cuando se complete responseFuture#complete, se notificará a asyncRpcResult#get para desbloquear.

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

 @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
    
    
        RpcInvocation inv = (RpcInvocation) invocation;
        ExchangeClient currentClient;
        if (clients.length == 1) {
    
    
            currentClient = clients[0];
        } else {
    
    
            // 轮询使用clients
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
    
    
            // isOneway为true,表示请求不需要拿结果
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
            // 拿当前方法的所配置的超时时间,默认为1000,1秒
            int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);
            if (isOneway) {
    
    
            //省略
            } else {
    
    
                AsyncRpcResult asyncRpcResult = new AsyncRpcResult(inv);
                // 异步去请求,得到一个CompletableFuture
                CompletableFuture<Object> responseFuture = currentClient.request(inv, timeout);

                // responseFuture会完成后会调用asyncRpcResult中的方法,这里并不会阻塞,如果要达到阻塞的效果在外层使用asyncRpcResult去控制
                asyncRpcResult.subscribeTo(responseFuture);
                // save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
                FutureContext.getContext().setCompatibleFuture(responseFuture);
                return asyncRpcResult;
            }
        } catch (TimeoutException e) {
    
    
        } catch (RemotingException e) {
    
    
        }
    }
}

Ejecute el cliente aquí para devolver responseFuture y regístrelo como DubboInvoker#responseFuture

3. Ejecución del cliente: HeaderExchangeChannel#request

Cree un método DefaultFuture#newFuture, cree una instancia de DefaultFuture, establezca DefaultFuture como valor y coloque la clave como ID de solicitud en la memoria caché FUTURES;

    @Override
    public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
    
    
        // create request.
        Request req = new Request();
        req.setVersion(Version.getProtocolVersion());
        req.setTwoWay(true);
        req.setData(request);
        DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
        try {
    
    
            channel.send(req);
        } catch (RemotingException e) {
    
    
            future.cancel();
            throw e;
        }
        return future;
    }

Futuro predeterminado#nuevofuturo

Mantener una instancia de FUTURES de caché local;

public class DefaultFuture extends CompletableFuture<Object> {
    
    

    private static final Logger logger = LoggerFactory.getLogger(DefaultFuture.class);

    private static final Map<Long, Channel> CHANNELS = new ConcurrentHashMap<>();

    private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<>();

    public static final Timer TIME_OUT_TIMER = new HashedWheelTimer(
            new NamedThreadFactory("dubbo-future-timeout", true),
            30,
            TimeUnit.MILLISECONDS);

    // invoke id.
    private final Long id;
    private final Channel channel;
    private final Request request;
    private final int timeout;
    private final long start = System.currentTimeMillis();
    private volatile long sent;
    private Timeout timeoutCheckTask;

    private DefaultFuture(Channel channel, Request request, int timeout) {
    
    
        this.channel = channel;
        this.request = request;
        this.id = request.getId();
        this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
        // put into waiting map.
        FUTURES.put(id, this);
        CHANNELS.put(id, channel);
    }
}

Hasta ahora, la relación es la siguiente: AsyncToSyncInvoker#asyncResult => Suscripción => DubboInvoker#responseResult => Poner en caché => DEFUTURES#DefaultFuture;

4. Ejecución del servidor: AbstractProxyInvoker#invoke

  1. Llame al método doInvoke, pase la instancia del proxy proxy, el nombre del método nombreMétodo, el tipo de parámetro tipos de parámetros, los argumentos de los parámetros del método, devuelva un valor de objeto;
  2. Instale la onda de valor de valor de retorno del objeto como el futuro de la instancia CompleteFuture;
  3. Crear una instancia de AsyncRpcResult asyncRpcResult
  4. Cuando se ejecuta el método, la configuración llamará al método future.whenComplete. En el método de devolución de llamada, cree una instancia de AppResponse, que representa el contenido de la respuesta, y establezca el contenido de la respuesta de acuerdo con si ocurre una excepción; luego llame el método de asyncRpcResult#complete para establecer el contenido del resultado de la respuesta en asyncRpcResult
  5. devolver asyncRpcResult;
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
    
    

    @Override
    public Result invoke(Invocation invocation) throws RpcException {
    
    
        try {
    
    
            // 执行服务,得到一个接口,可能是一个CompletableFuture(表示异步调用),可能是一个正常的服务执行结果(同步调用)
            // 如果是同步调用会阻塞,如果是异步调用不会阻塞
            Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());

            // 将同步调用的服务执行结果封装为CompletableFuture类型
            CompletableFuture<Object> future = wrapWithFuture(value, invocation);

            // 异步RPC结果
            AsyncRpcResult asyncRpcResult = new AsyncRpcResult(invocation);

            //设置一个回调,如果是异步调用,那么服务执行完成后将执行这里的回调
            // 不会阻塞
            future.whenComplete((obj, t) -> {
    
    
                AppResponse result = new AppResponse();
                if (t != null) {
    
    
                    if (t instanceof CompletionException) {
    
    
                        result.setException(t.getCause());
                    } else {
    
    
                        result.setException(t);
                    }
                } else {
    
    
                    result.setValue(obj);
                }
                // 将服务执行完之后的结果设置到异步RPC结果对象中
                asyncRpcResult.complete(result);
            });

            // 返回异步RPC结果
            return asyncRpcResult;
        } catch (InvocationTargetException e) {
    
    
            // 假设抛的NullPointException,那么会把这个异常包装为一个Result对象
            return AsyncRpcResult.newDefaultAsyncResult(null, e.getTargetException(), invocation);
        } catch (Throwable e) {
    
    
        //抛出异常
    }

    private CompletableFuture<Object> wrapWithFuture (Object value, Invocation invocation) {
    
    
        if (RpcContext.getContext().isAsyncStarted()) {
    
    
            return ((AsyncContextImpl)(RpcContext.getContext().getAsyncContext())).getInternalFuture();
        } else if (value instanceof CompletableFuture) {
    
    
            return (CompletableFuture<Object>) value;
        }
        return CompletableFuture.completedFuture(value);
    }

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

El futuro aquí se registra como AbstractProxyInvoker#future, y asyncRpcResult devuelve el HeaderExchangeHandler#future de la capa anterior

2. El servidor ejecuta HeaderExchangeHandler#hadnleRequest

  1. Cree una instancia de objeto de Respuesta, establezca el ID de la solicitud, el número de versión;
  2. Llame al siguiente método handler#reply para procesar la solicitud y devolver una instancia de CompletionStage, que es la instancia asyncRpcResult devuelta anteriormente.
  3. Llame al método CompletionStage#whenComplete, si se completa la ejecución de la solicitud, se activará el método de devolución de llamada;
    [Cuando (1) AbstractProxyInvoker#invoke llama al método asyncRpcResult#complete, se activará el método whenComplete actual]
    Si se produce una excepción durante la ejecución , , el estado de retorno es error de llamada de servicio SERVICE_ERROR, establezca el resultado en información de excepción;
    si no se produce ninguna excepción durante la ejecución, el estado de retorno es Response.OK, establezca el resultado de retorno en apResult, que representa los datos devueltos por la solicitud
  4. Llame al método channel#send para enviar datos al cliente;
void handleRequest(final ExchangeChannel channel, Request req) throws RemotingException {
    
    
        // 请求id,请求版本
        Response res = new Response(req.getId(), req.getVersion());


        // 获取 data 字段值,也就是 RpcInvocation 对象,表示请求内容
        // find handler by message class.
        Object msg = req.getData();
        try {
    
    
            // 继续向下调用,分异步调用和同步调用,如果是同步则会阻塞,如果是异步则不会阻塞
            CompletionStage<Object> future = handler.reply(channel, msg);   // 异步执行服务

            // 如果是同步调用则直接拿到结果,并发送到channel中去
            // 如果是异步调用则会监听,直到拿到服务执行结果,然后发送到channel中去
            future.whenComplete((appResult, t) -> {
    
    
                try {
    
    
                    if (t == null) {
    
    
                        res.setStatus(Response.OK);
                        res.setResult(appResult);
                    } else {
    
    
                        // 服务执行过程中出现了异常,则把Throwable转成字符串,发送给channel中,也就是发送给客户端
                        res.setStatus(Response.SERVICE_ERROR);
                        res.setErrorMessage(StringUtils.toString(t));
                    }
                    channel.send(res);
                } catch (RemotingException e) {
    
    
                    logger.warn("Send result to consumer failed, channel is " + channel + ", msg is " + e);
                } finally {
    
    
                    // HeaderExchangeChannel.removeChannelIfDisconnected(channel);
                }
            });
        } catch (Throwable e) {
    
    
            res.setStatus(Response.SERVICE_ERROR);
            res.setErrorMessage(StringUtils.toString(e));
            channel.send(res);
        }
    }

Aquí, la relación futura del lado del servidor AbstractProxyInvoker#future#complete => trigger => AbstractProxyInvoker#future#whenComplete callback, call HeaderExchangeHandler#future#complete => trigger HeaderExchangeHandler#future#whenComplete => channel#send devuelve los datos de respuesta Response
;

3. El cliente ejecuta HeaderExchangeHandler#hadnleResponse

Después de que el cliente envía la solicitud, el servidor devuelve los datos de respuesta. El tipo de datos recibido por el cliente es Respuesta, y se llamará a handleResponse para procesar el resultado de la respuesta;

    static void handleResponse(Channel channel, Response response) throws RemotingException {
    
    
        if (response != null && !response.isHeartbeat()) {
    
    
            DefaultFuture.received(channel, response);
        }
    }

  • Cuando el cliente solicita datos, el método channel#send de Netty envía datos de forma asíncrona, los devuelve inmediatamente después del envío y no tiene valor de retorno.Para esperar los datos devueltos, el ejecutor asincrónico a síncrono AsyncToSyncInvoker esperará indefinidamente;
  • Cuando el cliente llama al método de solicitud en HeaderExchangeChannel, creará una instancia de DefaultFuture y la colocará en la memoria caché DEFUTURES, la clave es el ID de solicitud y el valor es DefaultFuture;
  • Cuando se devuelva el resultado de la respuesta, en DefaultFuture#received, se obtendrá la instancia de DefaultFuture de la caché de Futures según el ID de la respuesta.Si el futuro está vacío, significa que se ha agotado el tiempo de espera. Si no está vacío, llame al método future#doreceived para procesar el valor devuelto;
  • En doReceived, si el estado es Response.OK, establezca el valor de retorno appResult en el futuro a través de Future#complete, que representa el valor de retorno del futuro bloqueado, es decir, el resultado de la ejecución del servidor
  • Si se agota el tiempo de espera, llame a completeExceptionally para generar una excepción de tiempo de espera;
  • Si ocurre una excepción comercial, la información de la excepción de llamada remota se mostrará en el cliente como valor de retorno;
  • Este es el mecanismo asíncrono a síncrono de Dubbo; el canal entre Spring y Redis, y el mecanismo asíncrono a síncrono de openFeign son similares;
public class DefaultFuture extends CompletableFuture<Object> {
    
    
    public static void received(Channel channel, Response response) {
    
    
        received(channel, response, false);
    }

    public static void received(Channel channel, Response response, boolean timeout) {
    
    
        try {
    
    
            // response的id,
            DefaultFuture future = FUTURES.remove(response.getId());
            if (future != null) {
    
    
                Timeout t = future.timeoutCheckTask;
                if (!timeout) {
    
    
                    // decrease Time
                    t.cancel();
                }
                future.doReceived(response);
            } else {
    
    
                logger.warn("The timeout response finally returned at "
                        + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                        + ", response " + response
                        + (channel == null ? "" : ", channel: " + channel.getLocalAddress()
                        + " -> " + channel.getRemoteAddress()));
            }
        } finally {
    
    
            CHANNELS.remove(response.getId());
        }
    }
    private void doReceived(Response res) {
    
    
        if (res.getStatus() == Response.OK) {
    
    
            this.complete(res.getResult());
        } else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
    
    
            this.completeExceptionally(new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()));
        } else {
    
    
            this.completeExceptionally(new RemotingException(channel, res.getErrorMessage()));
        }
    }
}

En este punto, cuando el servidor envía datos de respuesta al cliente, => método DEFUTURES#DefaultFuture#complete,
significa que se completó la ejecución de DubboInvoker#responseResult y notifica =》AsyncToSyncInvoker#asyncResult#get para desbloquear;

Haz un dibujo de la siguiente manera:

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Manejo de excepciones Dubbo

InvocadorInvocaciónHandler#invoke

public class InvokerInvocationHandler implements InvocationHandler {
    
    
    private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);
    private final Invoker<?> invoker;

    public InvokerInvocationHandler(Invoker<?> handler) {
    
    
        this.invoker = handler;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        String methodName = method.getName();
        // 这里的recreate方法很重要,他会调用AppResponse的recreate方法,
        // 如果AppResponse对象中存在exception信息,则此方法中会throw这个异常
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }
}

invocador.invocar(nuevo RpcInvocación(método, argumentos)) devuelve una instancia de objeto Respuesta, que es el resultado de la respuesta,
llame al método recrear para obtener el contenido de la respuesta AppResponse;

recrear#recrear

Llame al método getAppResponse para obtener el contenido de la respuesta AppResponse, luego llame al método AppResponse#recreate;

public class AsyncRpcResult extends AbstractResult {
    
    
    @Override
    public Object recreate() throws Throwable {
    
    
        RpcInvocation rpcInvocation = (RpcInvocation) invocation;
        FutureAdapter future = new FutureAdapter(this);
        RpcContext.getContext().setFuture(future);
        if (InvokeMode.FUTURE == rpcInvocation.getInvokeMode()) {
    
    
            return future;
        }

        return getAppResponse().recreate();
    }

}

AppResponse#recreate

Determinar si existe la excepción del contenido de la respuesta;
obtener el tipo de excepción si existe;
establecer la información de la pila de errores,

    @Override
    public Object recreate() throws Throwable {
    
    
        if (exception != null) {
    
    
            // fix issue#619
            try {
    
    
                // get Throwable class
                Class clazz = exception.getClass();
                while (!clazz.getName().equals(Throwable.class.getName())) {
    
    
                    clazz = clazz.getSuperclass();
                }
                // get stackTrace value
                Field stackTraceField = clazz.getDeclaredField("stackTrace");
                stackTraceField.setAccessible(true);
                Object stackTrace = stackTraceField.get(exception);
                if (stackTrace == null) {
    
    
                    exception.setStackTrace(new StackTraceElement[0]);
                }
            } catch (Exception e) {
    
    
                // ignore
            }
            throw exception;
        }
        return result;
    }

Cuando el proveedor de servicios ejecuta el servicio, si ocurre una excepción, el marco capturará la excepción. La lógica para capturar la excepción está en AbstractProxyInvoker. Después de capturar la excepción, empaquetará la información de excepción en un objeto AppResponse normal, pero el valor el atributo de AppResponse no es Valor, el atributo de excepción tiene un valor;

Después de eso, el proveedor de servicios enviará el objeto AppResponse al consumidor del servicio. El consumidor del servicio llama al método recreate de AppResponse en el InvokerInvocationHandler para obtener un nuevo resultado. En el método recreate, fallará si el objeto AppResponse es normal, eso es, si hay una información de excepción, si existe, lanzar esta excepción directamente, de modo que la excepción que ocurre durante la ejecución del servicio se lanza al consumidor del servicio.

Entonces, hay un problema aquí, si la clase de excepción lanzada por el proveedor de servicios no existe en el lado del consumidor del servicio, entonces el consumidor del servicio no podrá lanzar esta excepción, entonces, ¿cómo lo maneja dubbo?

Esto implica ExceptionFilter, que es un filtro del lado del proveedor de servicios. Principalmente identifica las excepciones después de que el proveedor de servicios termina de ejecutar el servicio:

  1. Si se trata de una excepción que debe detectar el desarrollador, ignórela y devuélvala directamente al consumidor.
  2. Si hay una declaración en la firma del método ejecutado actualmente, ignórela y devuelva la excepción directamente al consumidor
  3. Si no es necesario que el desarrollador detecte la excepción lanzada, o si no hay una declaración sobre el método, el servidor registrará un registro de errores.
  4. Si la clase de excepción y la clase de interfaz están en el mismo paquete jar, ignórelo y devuelva la excepción directamente al consumidor.
  5. Si la clase de excepción es una excepción que viene con JDK, ignórela y devuelva la excepción al consumidor directamente
  6. Si la clase de excepción es una excepción que viene con Dubbo, ignórela y devuelva la excepción al consumidor directamente
  7. De lo contrario, envuelva la información de excepción en RuntimeException y anule el atributo de excepción en el objeto AppResponse.

Resumir

Consumidor

  1. MockClusterInvoker.invoke(nueva RpcInvocación(método, argumentos)):Mock逻辑
  2. AbstractClusterInvoker.invoke(invocación): agregue los archivos adjuntos establecidos en RpcContext al objeto de invocación, llame a la cadena de enrutamiento para filtrar el invocador de servicio adecuado del directorio de servicios y obtenga el equilibrio de carga de la política de equilibrio de servicios
  3. FailoverClusterInvoker.doInvoke(invocación, invocadores, equilibrio de carga): seleccione un invocador de acuerdo con la estrategia de equilibrio de carga y luego ejecute
  4. InvokerWrapper.invoke(invocación): no hizo nada
  5. CallbackRegistrationInvoker.invoke(invocación): Comience a ejecutar la cadena Filter. Una vez completada la ejecución, se obtendrá el listener en ListenableFilter y se ejecutará el método onResponse del listener.
  6. ConsumerContextFilter.invoke(invocación): establezca los parámetros LocalAddress, RemoteAddress, RemoteApplicationName en RpcContext
  7. FutureFilter.invoke(invocación):
  8. MonitorFilter.invoke(invocación): El número de ejecuciones del método +1
  9. ListenerInvokerWrapper.invoke(invocación): no hizo nada
  10. AsyncToSyncInvoker.invoke(invocación): de asíncrono a síncrono, primero usará el invocador subyacente para ejecutarse de forma asíncrona y luego bloqueará el tiempo Integer.MAX_VALUE hasta que se obtenga el resultado
  11. AbstractInvoker.invoke(invocación): principalmente llama al método doInvoke de DubboInvoker.Si hay una excepción en el método doInvoker, se empaquetará y empaquetará en AsyncRpcResult
  12. DubboInvoker.doInvoke(invocación): sondeo de un cliente de los clientes para enviar datos. Si está configurado para no preocuparse por el resultado, llame al método de envío de ReferenceCountExchangeClient, de lo contrario, llame al método de solicitud de ReferenceCountExchangeClient
  13. ReferenceCountExchangeClient.request(Solicitud de objeto, tiempo de espera int): no hizo nada
  14. HeaderExchangeClient.request (Solicitud de objeto, tiempo de espera int): no hizo nada
  15. HeaderExchangeChannel.request (Solicitud de objeto, tiempo de espera int): construya un objeto de solicitud y construya un objeto DefaultFuture para bloquear el tiempo de espera para esperar el resultado. Al construir el objeto DefaultFuture, el objeto DefaultFuture y la identificación requerida se almacenarán en FUTUROS, FUTURES es un mapa. Cuando HeaderExchangeHandler recibe el resultado, obtendrá el objeto DefaultFuture del mapa de acuerdo con la identificación y luego devolverá la respuesta.
  16. AbstractPeer.send (mensaje de objeto): obtenga el parámetro de envío de la URL, el valor predeterminado es falso
  17. AbstractClient.send (mensaje de objeto, booleano enviado): no hace nada
  18. NettyChannel.send (mensaje de objeto, booleano enviado): llame a writeAndFlush de NioSocketChannel para enviar datos, y luego juzgue si el envío es verdadero, luego bloquee el tiempo de espera especificado en la URL, porque si el envío es falso, el tiempo de espera se bloqueará en HeaderExchangeChannel
  19. NioSocketChannel.writeAndFlush(Object msg): los datos de envío sin bloqueo de Netty de nivel inferior

Resumen del consumidor

  1. La capa más externa es lógica simulada, simulacro antes de llamar y después de llamar
  2. Desde el directorio de servicios, filtre algunos invocadores de servicios (DubboInvoker) de acuerdo con el método invocado actualmente y la cadena de enrutamiento
  3. Equilibre la carga del invocador de servicio y seleccione un invocador de servicio
  4. Ejecutar la cadena de filtros
  5. AsyncToSyncInvoker completa de asincrónico a sincrónico, porque la ejecución de DubboInvoker es asíncrona y no bloqueante, por lo que si es una llamada sincrónica, se bloqueará aquí hasta que se obtenga el resultado de la respuesta.
  6. DubboInvoker inicia una llamada asíncrona sin bloqueo
  7. HeaderExchangeChannel bloqueará el tiempo de espera para esperar el resultado. Este tiempo de espera es el tiempo de espera configurado por el usuario del lado del consumidor.

Servidor

  1. NettyServerHandler: recibir datos
  2. MultiMessageHandler: determine si los datos recibidos son un MultiMessage, si es así, obtenga un solo mensaje en el MultiMessage y páselo a HeartbeatHandler para su procesamiento.
  3. HeartbeatHandler: determine si se trata de un mensaje de latido y, en caso contrario, pase el mensaje a AllChannelHandler
  4. AllChannelHandler: encapsule el mensaje recibido en un objeto ChannelEventRunnable y tírelo al grupo de subprocesos para su procesamiento.
  5. ChannelEventRunnable: en el método de ejecución de ChannelEventRunnable, se llamará a DecodeHandler para procesar el mensaje
  6. DecodeHandler: de acuerdo con el formato de datos del protocolo Dubbo, analice la ruta, la versión, el método, los parámetros del método, etc. de la solicitud actual y luego pase la solicitud analizada a HeaderExchangeHandler
  7. HeaderExchangeHandler: para procesar los datos de la solicitud, primero construya un objeto de respuesta, luego llame a ExchangeHandlerAdapter para obtener un futuro de CompletionStage y luego vincule una función de devolución de llamada al futuro a través de whenComplete.Después de ejecutar el futuro, puede obtener el resultado de ejecución de ExchangeHandlerAdapter desde la función de devolución de llamada, y establezca el resultado de la ejecución en el objeto de respuesta y envíelo a través del canal.
  8. ExchangeHandlerAdapter: busque el objeto Exportador del Exportador exportado de la máquina de acuerdo con la clave de servicio correspondiente a la Solicitud actual, obtenga el Invocador del Exportador y luego ejecute el método de invocación.El Invocador es ProtocolFilterWrapper$CallbackRegistrationInvoker
  9. ProtocolFilterWrapper$CallbackRegistrationInvoker: responsable de ejecutar la cadena de filtros y devolver la llamada al método onResponse o onError de cada filtro después de la ejecución
  10. EchoFilter: determina si la solicitud actual es una prueba de eco, de ser así, la cadena de filtros no seguirá ejecutándose (el implementador del servicio Invoker no lo llamará)
  11. ClassLoaderFilter: establece el cargador de clases del subproceso actual en el cargador de clases correspondiente a la interfaz de servicio que se ejecutará actualmente
  12. GenericFilter: envuelve la información enviada por la llamada de generalización en un objeto RpcInvocación
  13. ContextFilter: establece los parámetros de RpcContext.getContext()
  14. TraceFilter: ejecute primero el método de invocación del siguiente invocador y registre la información de la llamada después de que la llamada sea exitosa
  15. TimeoutFilter: no hay un procesamiento especial al llamar, solo registre la hora actual, cuando se devuelva la llamada al método onResponse de TimeoutFilter después de que se ejecute toda la cadena de filtros, juzgará si la llamada ha excedido el tiempo de espera
  16. MonitorFilter: registra los tiempos de ejecución del servicio actual
  17. ExceptionFilter: no hay un procesamiento especial al llamar. Cuando se devuelve la llamada al método onResponse, se procesan diferentes excepciones. Explique el manejo de excepciones de Dubbo en detalle.
  18. DelegateProviderMetaDataInvoker: el final de la cadena de filtro, llama al siguiente Invoker
  19. AbstractProxyInvoker: cuando se exporta el servicio, de acuerdo con la interfaz del servicio, se genera el objeto de la clase de implementación del servicio y su método de invocación ejecutará el método del objeto de la clase de implementación del servicio para obtener el resultado.

Supongo que te gusta

Origin blog.csdn.net/yaoyaochengxian/article/details/124650104
Recomendado
Clasificación