当前位置:首页 > 公众号精选 > 架构师社区
[导读]I作者:vivo互联网服务器团队-WangGenfu一、Dubbo分层整体设计概述我们先从下图开始简单介绍Dubbo分层设计概念:(引用自Duboo开发指南-框架设计文档)如图描述Dubbo实现的RPC整体分10层:service、config、proxy、registry、cl...

I作者:vivo互联网服务器团队-Wang Genfu

一、Dubbo分层整体设计概述


我们先从下图开始简单介绍Dubbo分层设计概念:


源码解读Dubbo分层设计思想

(引用自Duboo开发指南-框架设计文档


如图描述Dubbo实现的RPC整体分10层:service、config、proxy、registry、cluster、monitor、protocol、exchange、transport、serialize。


  • service:使用方定义的接口和实现类;

  • config:负责解析Dubbo定义的配置,比如注解和xml配置,各种参数;

  • proxy:主要负责生成消费者和提供者的代理对象,加载框架功能,比如提供者过滤器链,扩展点;

  • registry:负责注册服务的定义和实现类的装载;

  • cluster:只有消费者有这么一层,负责包装多个服务提供者成一个‘大提供者’,加载负载均衡、路有等扩展点;

  • monitor:定义监控服务,加载监控实现提供者;

  • protocol:封装RPC调用接口,管理调用实体的生命周期;

  • exchange:封装请求响应模式,同步转异步;

  • transport:抽象传输层模型,兼容netty、mina、grizzly等通讯框架;

  • serialize:抽象序列化模型,兼容多种序列化框架,包括:fastjson、fst、hessian2、kryo、kryo2、protobuf等,通过序列化支持跨语言的方式,支持跨语言的rpc调用;


Dubbo这么分层的目的在于实现层与层之间的解耦,每一层都定义了接口规范,也可以根据不同的业务需求定制、加载不同的实现,具有极高的扩展性。


1.1. RPC调用过程


接下来结合上图简单描述一次完整的rpc调用过程:


Dubbo分层的角度看,详细时序图如下,蓝色部分是服务消费端,浅绿色部分是服务提供端,时序图从消费端一次Dubbo方法调用开始,到服务端本地方法执行结束。


源码解读Dubbo分层设计思想


Dubbo核心领域对象的角度看,我们引用Dubbo官方文档说明,如下图所示。Dubbo核心领域对象是Invoker,消费端代理对象是proxy,包装了Invoker的调用;服务端代理对象是一个Invoker,他通过exporter包装,当服务端接收到调用请求后,通过exporter找到Invoker,Invoker去实际执行用户的业务逻辑。


源码解读Dubbo分层设计思想

(引用自Dubbo官方文档)


1.2 Dubbo服务的注册和发现流程


下图出自开发指南-框架设计-引用服务时序,主要流程是:从注册中心订阅服务提供者,然后启动tcp服务连接远端提供者,将多个服务提供者合并成一个Invoker,用这个Invoker创建代理对象。


源码解读Dubbo分层设计思想


下图出自开发指南-框架设计-暴露服务时序,主要流程是:创建本地服务的代理Invoker,启动tcp服务暴露服务,然后将服务注册到注册中心。


源码解读Dubbo分层设计思想


接下来我们结合Dubbo服务的注册和发现,从配置层开始解释每一层的作用和原理。


示例服务接口定义如下:

public interface CouponServiceViewFacade { /** * 查询单张优惠券 */ CouponViewDTO query(String code);}

二、配置层


2.1. 做什么


配置层提供配置处理工具类,在容器启动的时候,通过ServiceConfig.export实例化服务提供者,ReferenceConfig.get实例化服务消费者对象。


Dubbo应用使用spring容器启动时,Dubbo服务提供者配置处理器通过ServiceConfig.export启动Dubbo远程服务暴露本地服务。Dubbo服务消费者配置处理器通过ReferenceConfig.get实例化一个代理对象,并通过注册中心服务发现,连接远端服务提供者。


Dubbo配置可以使用注解和xml两种形式,本文采用注解的形式进行说明。


2.2. 怎么做


2.2.1 服务消费端的解析


Spring容器启动过程中,填充bean属性时,对含有Dubbo引用注解的属性使用

org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor进行初始化。


如下是

ReferenceAnnotationBeanPostProcessor的构造方法,Dubbo服务消费者注解处理器处理以下三个注解:

DubboReference.class

Reference.class

com.alibaba.dubbo.config.annotation.Reference.class修饰的类。


ReferenceAnnotationBeanPostProcessor类定义:

public class ReferenceAnnotationBeanPostProcessor extends AbstractAnnotationBeanPostProcessor implements ApplicationContextAware { public ReferenceAnnotationBeanPostProcessor() { super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class); }}

Dubbo服务发现到这一层,Dubbo即将开始构建服务消费者的代理对象,

CouponServiceViewFacade接口的代理实现类。


2.2.2 服务提供端的解析


Spring容器启动的时候,加载注解

@org.apache.dubbo.config.spring.context.annotation.DubboComponentScan指定范围的类,并初始化;初始化使用dubbo实现的扩展点

org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor。


ServiceClassPostProcessor处理的注解类有

DubboService.class,Service.class,com.alibaba.dubbo.config.annotation.Service.class


如下是ServiceClassPostProcessor类定义:

public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { private final static List> serviceAnnotationTypes = asList( DubboService.class,Service.class,com.alibaba.dubbo.config.annotation.Service.class );。。。}

等待Spring容器ContextRefreshedEvent事件,启动Dubbo应用服务监听端口,暴露本地服务。


Dubbo服务注册到这一层,Dubbo即将开始构建服务提供者的代理对象,CouponServiceViewFacade实现类的反射代理类。


三、 代理层


3.1 做什么


为服务消费者生成代理实现实例,为服务提供者生成反射代理实例。


CouponServiceViewFacade的代理实现实例,消费端在调用query方法的时候,实际上是调用代理实现实例的query方法,通过他调用远程服务。

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

CouponServiceViewFacade的反射代理实例,服务端接收到请求后,通过该实例的Invoke方法最终执行本地方法query。

/** * InvokerWrapper */public class AbstractProxyInvoker implements Invoker { // 。。。 public AbstractProxyInvoker(CouponServiceViewFacade proxy, Class type, URL url) { //。。。 this.proxy = proxy; this.type = type; this.url = url; } @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); } }

3.2 怎么做


Dubbo代理工厂接口定义如下,定义了服务提供者和服务消费者的代理对象工厂方法。服务提供者代理对象和服务消费者代理对象都是通过工厂方法创建,工厂实现类可以通过SPI自定义扩展。

@SPI("javassist")public interface ProxyFactory { // 生成服务消费者代理对象 @Adaptive({PROXY_KEY}) T getProxy(Invoker invoker) throws RpcException; // 生成服务消费者代理对象 @Adaptive({PROXY_KEY}) T getProxy(Invoker invoker, boolean generic) throws RpcException; // 生成服务提供者代理对象 @Adaptive({PROXY_KEY}) Invoker getInvoker(T proxy, Class type, URL url) throws RpcException; }

3.2.1 服务消费者


3.2.1.1 创建服务消费者代理类


默认采用Javaassist代理工厂实现,Proxy.getProxy(interfaces)创建代理工厂类,newInstance创建具体代理对象。

public class JavassistProxyFactory extends AbstractProxyFactory { @Override @SuppressWarnings("unchecked") public T getProxy(Invoker invoker, Class[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } 。。。 }

3.2.1.2 服务消费者代理


Dubbo为每个服务消费者生成两个代理类:代理工厂类,接口代理类。


CouponServiceViewFacade代理工厂类:

public class Proxy1 extends Proxy implements DC { public Proxy1() { } public Object newInstance(InvocationHandler var1) { return new proxy1(var1); }}

最终生成的CouponServiceViewFacade的代理对象如下,其中handler的实现类是InvokerInvocationHandler,

this.handler.invoke方法发起Dubbo调用。

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

3.2.2 服务提供者


3.2.2.1 创建服务提供者代理类


默认Javaassist代理工厂实现,使用Wrapper包装本地服务提供者。proxy是实际的服务提供者实例,即CouponServiceViewFacade的本地实现类,type是接口类定义,URL是injvm协议URL。

public class JavassistProxyFactory extends AbstractProxyFactory { 。。。 @Override public Invoker getInvoker(T proxy, Class type, URL url) { // 代理包装类,包装了本地的服务提供者 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); // 代理类入口 return new AbstractProxyInvoker(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; } }

3.2.2.2 Wrapper包装类


Dubbo为每个服务提供者的本地实现生成一个Wrapper代理类,抽象Wrapper类定义如下:

public abstract class Wrapper { 。。。 abstract public Object invokeMethod(Object instance, String mn, Class[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;}

具体Wrapper代理类使用字节码技术动态生成,本地服务CouponServiceViewFacade的代理包装类举例:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)// package org.apache.dubbo.common.bytecode; import com.xxx.CouponServiceViewFacade;import java.lang.reflect.InvocationTargetException;import java.util.Map;import org.apache.dubbo.common.bytecode.ClassGenerator.DC; public class Wrapper25 extends Wrapper implements DC { 。。。 public Wrapper25() { } public Object invokeMethod(Object var1, String var2, Class[] var3, Object[] var4) throws InvocationTargetException { CouponServiceViewFacade var5; try { var5 = (CouponServiceViewFacade)var1; } catch (Throwable var8) { throw new IllegalArgumentException(var8); } try { if ("query".equals(var2)
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭
关闭