Overview of Dubbo Layered Architecture and Design
The article by the Vivo Internet Server Team details Apache Dubbo’s ten‑layer architecture—service, config, proxy, registry, cluster, monitor, protocol, exchange, transport, and serialization—explaining each layer’s role, the RPC invocation flow, registration/discovery mechanisms, configuration options, and how Dubbo’s extensive SPI‑based modular design enables loose coupling, extensibility, and robust micro‑service development.
This article, authored by the Vivo Internet Server Team, provides a comprehensive technical overview of Apache Dubbo’s layered architecture, its design principles, and the implementation details of each layer.
1. Dubbo Layered Design Overview
Dubbo is divided into ten layers: service, config, proxy, registry, cluster, monitor, protocol, exchange, transport, and serialize. Each layer defines an interface contract, enabling loose coupling and high extensibility.
2. RPC Call Process
The article illustrates a complete RPC invocation flow from the consumer side to the provider side, showing how Dubbo’s core objects ( Invoker, Proxy, Exporter) interact.
The core domain object Invoker is highlighted, with the consumer proxy wrapping the invoker and the provider side exposing an Exporter that ultimately calls the user’s business logic.
3. Registration and Discovery
Dubbo registers services to a registry (e.g., Zookeeper) and discovers them via subscription. The process includes creating local proxy Invoker objects, starting TCP services, and publishing service URLs.
4. Configuration Layer
The configuration layer handles ServiceConfig.export for providers and ReferenceConfig.get for consumers. It supports both annotation‑based and XML‑based configurations.
Example service interface:
public interface CouponServiceViewFacade {
/**
* Query a single coupon
*/
CouponViewDTO query(String code);
}5. Proxy Layer
Dubbo generates proxy objects for both consumers and providers. The consumer proxy forwards method calls to the remote service, while the provider proxy invokes the local implementation.
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
package org.apache.dubbo.common.bytecode;
public class proxy1 implements DC, Destroyable, CouponServiceViewFacade, EchoService {
public static Method[] methods;
private InvocationHandler handler;
public proxy1(InvocationHandler var1) {
this.handler = var1;
}
public proxy1() {}
public CouponViewDTO query(String var1) {
Object[] var2 = new Object[]{var1};
Object var3 = this.handler.invoke(this, methods[0], var2);
return (CouponViewDTO) var3;
}
}The corresponding Invoker implementation:
public class AbstractProxyInvoker<CouponServiceViewFacade> implements Invoker<CouponServiceViewFacade> {
// ...
@Override
public Result invoke(Invocation invocation) throws RpcException {
Object value = doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments());
// ...
}
protected Object doInvoke(CouponServiceViewFacade proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
}6. Cluster Layer
The cluster layer aggregates multiple provider invokers into a single ClusterInvoker, applying routing and load‑balancing strategies (e.g., failover, failfast, round‑robin).
@SPI(Cluster.DEFAULT)
public interface Cluster {
String DEFAULT = FailoverCluster.NAME;
@Adaptive
<T> Invoker<T> join(Directory<T> directory) throws RpcException;
}Example AbstractClusterInvoker implementation shows how routing and load balancing are applied before invoking the actual provider.
public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
@Override
public Result invoke(final Invocation invocation) throws RpcException {
List<Invoker<T>> invokers = list(invocation);
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
return doInvoke(invocation, invokers, loadbalance);
}
// ...
}7. Monitor Layer
Dubbo provides monitoring of RPC call counts and latency via MonitorFactory, Monitor, and MonitorService interfaces.
@SPI("dubbo")
public interface MonitorFactory {
@Adaptive("protocol")
Monitor getMonitor(URL url);
}8. Protocol Layer
The protocol layer abstracts service exposure and reference. DubboProtocol opens server ports, optimizes serialization, and creates DubboInvoker for remote calls.
public class DubboProtocol extends AbstractProtocol {
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
openServer(url);
optimizeSerialization(url);
return exporter;
}
@Override
public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
optimizeSerialization(url);
DubboInvoker<T> invoker = new DubboInvoker<>(serviceType, url, getClients(url), invokers);
invokers.add(invoker);
return invoker;
}
}Key interfaces: Invoker, Exporter, Protocol.
9. Exchange Layer
The exchange layer converts synchronous calls to asynchronous ones, wrapping requests and responses.
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
@Override
public CompletableFuture<Object> reply(ExchangeChannel channel, Object message) throws RemotingException {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
Result result = invoker.invoke(inv);
return result.thenApply(Function.identity());
}
};10. Transport Layer
Transport abstracts the underlying network framework (Netty, Mina, Grizzly). The Transporter SPI selects the concrete implementation.
@SPI("netty")
public interface Transporter {
@Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;
@Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
Client connect(URL url, ChannelHandler handler) throws RemotingException;
}Example Netty channel wrapper:
final class NettyChannel extends AbstractChannel {
private NettyChannel(Channel channel, URL url, ChannelHandler handler) {
super(url, handler);
if (channel == null) {
throw new IllegalArgumentException("netty channel == null;");
}
this.channel = channel;
}
}11. Serialization Layer
Dubbo supports multiple serialization frameworks (fastjson, fst, Hessian2, Kryo, Protobuf). The Serialization SPI defines the contract.
@SPI("hessian2")
public interface Serialization {
byte getContentTypeId();
String getContentType();
@Adaptive
ObjectOutput serialize(URL url, OutputStream output) throws IOException;
@Adaptive
ObjectInput deserialize(URL url, InputStream input) throws IOException;
}The article concludes that Dubbo’s modular design, extensive use of SPI, and clear separation of concerns make it a robust foundation for building distributed micro‑service systems.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
