一.参考
https://cn.dubbo.apache.org/zh-cn/
dubbo spi的分析参考之前写的文章.
分析的代码版本为dubbo-2.7.X.
二.架构
(一)分层架构
参考官网架构图 http://dubbo.apache.org/books/dubbo-dev-book/design.html
从消费端来说,从上到下依次是
1.Service层,用户定义的业务接口
2.Config层,读取用户配置(比如超时时间,group等),主要是ServiceConfig,ReferenceConfig.
3.Proxy层,因为用户定义的都是接口,消费端需要具体类对象才能调用。统一实现JDK动态代理或者cglib,向下层做调用.主要是ServiceProxy,ProxyFactory等.
4.Registry层,实现注册中心的对接,从注册中心拉取服务端,消费端地址列表.主要类为Registry,RegistryFactory,RegistryService等.
5.Cluster层,集群层,主要处理比如路由黑白名单,负载均衡,集群中机器挂掉,调用失败的重试策略等.主要类为Cluster,Directory,Router,LoadBalance.
6.Monitor层.统计监控层,主要接口是Statistics,MonitorFactory,MonitorService.
7.Protocol层,主要处理使用哪种协议,比如dubbo还是http等.主要接口是Invocation,Result,Protocol,消费端的Invoker,服务端的Exporter等.消费端的接口的url到生产端的接口实现类在这里映射,存在org.apache.dubbo.rpc.protocol.dubbo.DubboExporter#delegateExporterMap中,key是url,value是接口的代理对象.
8.Exchange层,封装请求为Request,Response格式.主要接口为Exchanger,ExchangeChannel,ExchangeClient,ExchangeServer等.
9.Transport层,处理区分不同的网络框架,比如Netty,mina,包含网络请求,编解码器等.主要接口是Message,Channel,Transporter,Client,Codec,Server
10.序列化层,序列化请求对象.主要接口为Serialization,ObjectInput,ObjectOutput,ThreadPool
三.测试代码
1.服务端入口dubbo-demo的jar包下org.apache.dubbo.demo.provider.Application#main测试用例
四.源码分析
(一)spring启动
1.spring启动时读取dubbo的xml配置文件,和读取普通的spring的xml配置文件是一样的。进入DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(),这个方法之前的逻辑参考之前写的<spring源码分析之架构和Refresh>帖子.这个方法里面循环遍历xml里面的所有标签.因为是自定义标签,每个标签都进入BeanDefinitionParserDelegate#parseCustomElement().这个方法先调用DefaultNamespaceHandlerResolver#resolve()查找这个xml的解析类为DubboNamespaceHandler.进入DubboNamespaceHandler#init()注册xml的每个标签的解析类.代码如下
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
然后进入DubboBeanDefinitionParser#parse()解析xml中的xml标签.这里面会注册ApplicationConfig,RegistryConfig,ProtocolConfig,ServiceBean(用来处理dubbo:service标签)类等到DefaultListableBeanFactory#beanDefinitionMap().这里需要注意下解析<dubbo:service interface="xxx.xxx" ref="xxxid"/>标签的ServiceBean类.普通的<bean>标签由spring来处理,和dubbo没关系.ServiceBean会把xml中ref引用的bean name,从ApplicationContext中取出bean的定义.把ref引用bean的完整路径设置为ServiceBean的id和name,比如xxx.DemoService.这个ServiceBean作为独立的bean放到beanDefinitionMap中.
(二)导出service
导出service的调用栈如下图所示:
1.在ServiceBean#setApplicationContext()里面把Spring里面的ApplicationContext设置到Dubbo的SpringExtensionFactory#contexts成员属性里面.然后调用AbstractApplicationContext#addApplicationListener把dubbo设置为spring的观察者.
2.真正从spring调用到dubbo导出服务的接口的是进入到ServiceBean#afterPropertiesSet回调里面.这个是spring创建dubbo的接口的bean,比如DemoService.调用getBean()时,传入的beanName是前面获取的<dubbo:service>的ref引用的完整路径.所有的ServiceBean填充完对象属性,开始做这个ServiceBean的初始化操作,回调ServiceBean#afterPropertiesSet()方法.
3.在ServiceBean#afterPropertiesSet()里面.把ApplicationConfig,RegistryConfig,ProtocolConfig设置到ServiceBean里面.
4.spring启动回调链路AbstractApplicationContext#refresh->AbstractApplicationContext#finishRefresh->SimpleApplicationEventMulticaster#doInvokeListener->com.alibaba.spring.context.OnceApplicationContextEventListener#onApplicationEvent->DubboBootstrapApplicationListener#onApplicationContextEvent->DubboBootstrap#start->ServiceConfig#export->ServiceConfig#doExport方法.该方法代码如下:
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
//已经导出过,直接返回
if (exported) {
return;
}
exported = true;
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
/* 遍历ProviderConfig类的setXXX方法,然后调用.比如setQosPort(),具体的参数值从配置文件中取出.*/
checkDefault();
if (provider != null) {
if (application == null) {
application = provider.getApplication();
}
if (module == null) {
module = provider.getModule();
}
if (registries == null) {
registries = provider.getRegistries();
}
if (monitor == null) {
monitor = provider.getMonitor();
}
if (protocols == null) {
protocols = provider.getProtocols();
}
}
if (module != null) {
if (registries == null) {
registries = module.getRegistries();
}
if (monitor == null) {
monitor = module.getMonitor();
}
}
if (application != null) {
if (registries == null) {
registries = application.getRegistries();
}
if (monitor == null) {
monitor = application.getMonitor();
}
}
if (ref instanceof GenericService) {
interfaceClass = GenericService.class;
if (StringUtils.isEmpty(generic)) {
generic = Boolean.TRUE.toString();
}
} else {
try {
//创建dubbo接口的Class对象
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
//基本的是不是接口的检查.主要是防止在xml文件里面填一些不存在的配置项
checkInterfaceAndMethods(interfaceClass, methods);
//是不是xml里面ref引用的检查
checkRef();
generic = Boolean.FALSE.toString();
}
if (local != null) {
if ("true".equals(local)) {
local = interfaceName + "Local";
}
Class<?> localClass;
try {
localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(localClass)) {
throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
}
}
if (stub != null) {
if ("true".equals(stub)) {
stub = interfaceName + "Stub";
}
Class<?> stubClass;
try {
stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
if (!interfaceClass.isAssignableFrom(stubClass)) {
throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
}
}
/* 遍历ApplicationConfig类的setXXX方法,然后调用.比如setQosPort(),具体的参数值从配置文件中取出.*/
checkApplication();
//检查Resistry层配置
checkRegistry();
//检查Protocol层配置
checkProtocol();
appendProperties(this);
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
//导出服务,主要是向注册中心,比如zk节点上注册提供者dubbo接口的名称,路径,版本,ip等等.代码在后面分析
doExportUrls();
ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}
5.进入ServiceConfig#doExportUrls().dubbo可以配置接口导出到多个协议,针对每种协议,调用doExportUrlsFor1Protocol方法.
private void doExportUrls() {
//加载xml中配置的注册中心的配置,生成url,代码在后面6分析
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
//每个协议都导出到每个注册中心里面,代码后面7分析
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
6.创建注册的url地址
进入AbstractInterfaceConfig#loadRegistries.
protected List<URL> loadRegistries(boolean provider) {
checkRegistry();
List<URL> registryList = new ArrayList<URL>();
//遍历所有的注册中心配置
if (registries != null && registries.size() > 0) {
for (RegistryConfig config : registries) {
String address = config.getAddress();
if (address == null || address.length() == 0) {
address = Constants.ANYHOST_VALUE;
}
String sysaddress = System.getProperty("dubbo.registry.address");
if (sysaddress != null && sysaddress.length() > 0) {
address = sysaddress;
}
if (address != null && address.length() > 0
&& !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
Map<String, String> map = new HashMap<String, String>();
//添加ApplicationConfig,对应接口的哪个应用
appendParameters(map, application);
//添加RegistryConfig,注册中心地址
appendParameters(map, config);
map.put("path", RegistryService.class.getName());
map.put("dubbo", Version.getVersion());
map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
}
if (!map.containsKey("protocol")) {
//扩展机制加载协议的实现类,没有配置的话默认使用dubbo协议
if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
map.put("protocol", "remote");
} else {
map.put("protocol", "dubbo");
}
}
//根据map转成url格式
List<URL> urls = UrlUtils.parseURLs(address, map);
for (URL url : urls) {
url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
//添加xml中的zookeeper地址
url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
/*最后map转成url的格式为:
zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=1879&qos.port=22222×tamp=1583997678318
*/
if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
|| (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
registryList.add(url);
}
}
}
}
}
return registryList;
}
7.每种协议的导出
进入ServiceConfig#doExportUrlsFor1Protocol(),代码如下:
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
/* 省略部分代码,主要是读取配置,通过从上层导下层一次往map里面put,解决父子层级依赖关系问题.
最后就生成 值为{side=provider, application=demo-provider, methods=sayHello, qos.port=22222, dubbo=2.0.0, pid=1879,
interface=com.alibaba.dubbo.demo.DemoService, generic=false, timestamp=1583998111644} 的map */
...
if (ProtocolUtils.isGeneric(generic)) {
map.put("generic", generic);
map.put("methods", Constants.ANY_VALUE);
} else {
String revision = Version.getVersion(interfaceClass, version);
if (revision != null && revision.length() > 0) {
map.put("revision", revision);
}
//调用Wrapper#makeWrapper()动态生成dubbo接口的Wrapper封装类,在后面11处分析
//method指向dubbo接口的所有方法.
String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
...
}
//获取注册中心的地址和端口号
String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
/* 这里会加载Protocol扩展的实现类,代码在后面8分析*/
Integer port = this.findConfigedPorts(protocolConfig, name, map);
URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.hasExtension(url.getProtocol())) {
url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getExtension(url.getProtocol()).getConfigurator(url).configure(url);
}
String scope = url.getParameter(Constants.SCOPE_KEY);
// don't export when none is configured
if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
// export to local if the config is not remote (export to remote only when config is remote)
if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
//导出本地接口,同一个jvm进程,代码分析在后面的8
exportLocal(url);
}
// export to remote if the config is not local (export to local only when config is local)
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && registryURLs.size() > 0) {
//遍历所有注册中心的URL,这里一般就是Zookeeper的url.因为这里都是一个ServiceBean进来的,只有一个接口.
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
//加载监控中心的URL.默认本机的2181端口.
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
/* 创建远程dubbo调用的Invoker对象,和本地Injvm的过程类似,只是URL换了,进入10处. 返回的invoker还是JavassistProxyFactory创建的Invoker对象.
这个invoker会在DubboExporter#delegateExporterMap的value中存储,key是url,消费者调用时通过这个map映射到这个invoker,调用具体的业务接口的实现类*/
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
//封装远程dubbo调用的Invoker对象为DelegateProviderMetaDataInvoker格式.代码在后面15处.
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
/*远程dubbo调用的DelegateProviderMetaDataInvoker转成Exporter导出,后面16处分析.
这里的Protocol还是三个包装类{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper},但是第一个传入的是RegistryProtocol.三个实现类逆序调用.
所以最后进入的是RegistryProtocol#export()方法创建DestroyableExporter,后面16处分析.先进入ProtocolFilterWrapper.export()方法,后面13处分析.*/
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
}
this.urls.add(url);
}
8.查找协议导出端口时,加载协议扩展.协议扩展后面新开贴分析.代码如下,这里传入的protocolConfig是xml里面配置的<dubbo:protocol>内容,name是dubbo,map是前面读取的xml配置.
private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
Integer portToBind = null;
// parse bind port from environment
//读取环境变量里面配置的dubbo端口,不是xml配置的
String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
portToBind = parsePort(port);
// if there's no bind port found from environment, keep looking up.
if (portToBind == null) {
//这里读取到xml配置的端口
portToBind = protocolConfig.getPort();
if (provider != null && (portToBind == null || portToBind == 0)) {
portToBind = provider.getPort();
}
/* 动态扩展加载Protocol的所有实现类,调用Protocol#getDefaultPort()方法。这里有三个实现类{ProtocolFilterWrapper,QosProtocolWrapper,ProtocolListenerWrapper}.先加载到ProtocolFilterWrapper类.
ProtocolFilterWrapper的构造方法参数是Protocol对象,Protocol成员指向上一个Protocol实现类DubboProtocol.这一步通过ExtensionLoader#createExtension()方法实现.然后QosProtocolWrapper的成员指向
ProtocolFilterWrapper.ProtocolListenerWrapper的成员指向QosProtocolWrapper.实际这里返回的是DubboProtocol的端口 这块新开贴分析源码 */
final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
if (portToBind == null || portToBind == 0) {
portToBind = defaultPort;
}
if (portToBind == null || portToBind <= 0) {
portToBind = getRandomPort(name);
if (portToBind == null || portToBind < 0) {
portToBind = getAvailablePort(defaultPort);
putRandomPort(name, portToBind);
}
logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
}
}
// save bind port, used as url's key later
map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
// registry port, not used as bind port by default
String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
Integer portToRegistry = parsePort(portToRegistryStr);
if (portToRegistry == null) {
portToRegistry = portToBind;
}
return portToRegistry;
}
9.导出本地同一jvm进程的dubbo接口,同一jvm进程导出的对象不适用代理,直接导出接口实现类的原对象.
private void exportLocal(URL url) {
if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
/* 设置本地地址为 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0
&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=1879&qos.port=22222&side=provider×tamp=1583998111644 的格式 */
URL local = URL.valueOf(url.toFullString())
.setProtocol(Constants.LOCAL_PROTOCOL)
.setHost(LOCALHOST)
.setPort(0);
/* 这里两步操作
(1).proxyFactory.getInvoker()获取Invoker对象.ProxyFactory是spi动态扩展,进入ExtensionLoader#getExtension()方法。实现类只有一个StubProxyFactoryWrapper.它的构造方法传入的
ProxyFactory是JavassistProxyFactory.所以先调用StubProxyFactoryWrapper#getInvoker()->JavassistProxyFactory#getInvoker()(代码在后面10分析)创建Invoker代表dubbo接口调用的信息,
(2).protocol.export()也是动态扩展.这里还是三个实现类{QosProtocolWrapper,ProtocolListenerWrapper,ProtocolFilterWrapper}.InjvmProtocol在QosProtocolWrapper的构造方法里面传入.
这里是逆序调用,先调用ProtocolFilterWrapper#export(代码在后面12分析)->ProtocolListenerWrapper#export()(在13分析)->QosProtocolWrapper#export()(启动Qos的Server)->
InjvmProtocol#export().InjvmProtocol真正把Invoker对象转成Exporter对象导出,在14处分析。最终生成的是InjvmExporter被封装后的ListenerExporterWrapper. */
Exporter<?> exporter = protocol.export(
proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
}
}
10.创建Invoker.Invoker是代理对象,代理dubbo接口.
(1).如果是本地jvm协议,进入JavassistProxyFactory#getInvoker().方法参数proxy是前面调用时的xml中配置的ref标签值,实现类DemoServiceImpl. type是接口 com.alibaba.dubbo.demo.DemoService,url是前面创建的local的Url值 injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2434&qos.port=22222&side=provider×tamp=1584001039834.
(2).如果是远程dubbo调用,使用zk注册的,参数不一样。proxy不变,还是xml中ref标签引用的dubbo接口实现类,type不变,指向dubbo接口,url变成 registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222®istry=zookeeper×tamp=1584018965180 .
代码如下:
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
//这里的Wrapper是核心.封装了所有接口Class对象到实际对象的引用.成员在下面代码.这里的getWrapper()调到后面11处的动态创建Wrapper
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
/* 创建匿名类对象,所有的调用都会转到Wrapper#invokeMethod()方法中去调用.所有的对象,方法名,方法的参数类型,参数值都封装在Warpper对象中。*/
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
/* invokeMethod是在Wrapper类的makeWrapper()方法里面动态生成的.Wrapper类的成员里面有dubbo实现类,invokeMethod会调用到 真实实现类的方法里面。这里在模拟jdk的动态代理实现 */
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
这里返回的Invoker是个匿名内部类AbstractProxyInvoker.调用方法只有上面的doInvoke(),供外面的类调用.对象成员如下:
public abstract class AbstractProxyInvoker<T> implements Invoker<T> {
//接口的实现类
private final T proxy;
//接口的Class对象
private final Class<T> type;
//接口对应的注册中心url地址
private final URL url;
...
}
Wrapper类的成员,核心方法是invokeMethod,它是在makeWrapper()方法里面动态生成的.
public abstract class Wrapper {
//Class对象到实际实现对象的映射
private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
private static final Wrapper OBJECT_WRAPPER = {...}
}
动态生成的Wrapper类使用arthas的jad反编译如下:
11.动态拼字串创建dubbo接口的封装类.模拟动态代理功能.
入参为dubbo接口的Class对象
private static Wrapper makeWrapper(Class<?> c) {
if (c.isPrimitive())
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
String name = c.getName();
//获取ClassLoader
ClassLoader cl = ClassHelper.getClassLoader(c);
//拼接代理类的字符串代码.
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
...
//类名为wrapper + 自增序号,比如Wrapper0
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
//创建ClassGenerator对象
ClassGenerator cc = ClassGenerator.newInstance(cl);
cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
cc.setSuperClass(Wrapper.class);
...
try {
//创建封装类的Class
Class<?> wc = cc.toClass();
// setup static field.
...
//add by feivirus
//我自己加的,把Class对象打到文件里反编译
Wrapper result = (Wrapper) wc.newInstance();
String objName = getObjectName(result.getClass().getName());
generateProxyClassFile(objName, new Class<?>[]{result.getClass()});
//add end
return result;
} catch (RuntimeException e) {
...
}
}
12.建立Filter的过滤职责链,返回被内含Filter职责链的新的Invoker.这Invoker内部包含JavassistProxyFactory创建的Invoker.
进入ProtocolFilterWrapper#export()方法.代码如下:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//如果是远程registry协议,进入这个分支.直接调用ProtocolListenerWrapper.export()
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
//如果本地jvm,进入这里(1)先创建一个Filter接口实现类的职责链,代码在下面.(2)protocol指向ProtocolListenerWrapper,代码13分析
return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
/* 加载所有Filter接口的实现类,这里有EchoFilter,ClassLoaderFilter,GenericFilter,ContextFilter,TraceFilter,TimeoutFilter, MonitorFilter,ExceptionFilter八个*/
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
...
//集中式职责链,依次调用
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
...
};
}
}
return last;
}
13.创建Exporter的观察者Listener.
进入ProtocolListenerWrapper#export().
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
/* 如果是远程registry协议,进入这个分支.直接调用QosProtocolWrapper.export().启动QosServer.然后进入RegistryProtocol#export()后面16处分析. */
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
/* 本地jvm注册,进入这里.导出的Exporter的实现类为ListenerExporterWrapper。代码如下. 这里的protocol是动态扩展时构造方法传进来的,指向QosProtocolWrapper,所以调用QosProtocolWrapper#export()(本地jvm不启动qos servier.))->QosProtocolWrapper的protocol成员指向InjvmProtocol,在14处分析*/
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
public class ListenerExporterWrapper<T> implements Exporter<T> {
//实际创建的Exporter引用, 指向InjvmExporter.
private final Exporter<T> exporter;
private final List<ExporterListener> listeners;
}
14.真正实现Invoker到Exporter的转换.这里导出的Exporter在上面13处封装成了ListenerExporterWrapper,最终导出就是ListenerExporterWrapper。
进入InjvmProtocol#export(),代码如下:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
/* 创建InjvmExporter返回. 这里的invoker指向前面12处新创建的包含filter过滤链的Invoker.*/
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
InjvmExporter继承自AbstractExporter。代码如下:
class InjvmExporter<T> extends AbstractExporter<T> {
private final String key;
//这里的key是dubbo接口的全路径名,比如xxx.xxx.DemoService. value是InjvmExporter对象的this自身.
private final Map<String, Exporter<?>> exporterMap;
}
public abstract class AbstractExporter<T> implements Exporter<T> {
/* 这里的Invoker指向12处新创建的包含filter过滤链的Invoker.这个Invoker包含JavassistProxyFactory创建的Invoker2。
Invoker2内的proxy指向dubbo接口的实现类,比如DemoServiceImpl*/
private final Invoker<T> invoker;
private volatile boolean unexported = false;
}
15.远程Dubbo调用invoker包装类.
public class DelegateProviderMetaDataInvoker<T> implements Invoker {
//这里指向JavassistProxyFactory创建的Invoker对象.
protected final Invoker<T> invoker;
//指向dubbo中xml配置的解析<dubbo:service>标签的ServiceBean对象本身.
private ServiceConfig metadata;
}
16.远程dubbo调用的DelegateProviderMetaDataInvoker转成Exporter接口导出.
从上面13处QosProtocolWrapper.export()方法调用过来,进入RegistryProtocol#export().入参为上面的DelegateProviderMetaDataInvoker.代码如下:
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//export invoker
/*协议换成dubbo协议的url,即dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131
&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843&qos.port=22222&side=provider×tamp=1584018965207
导出,进入DubboProtocol#export(),导出dubbo协议的invoker,启动dubbo协议的本机的netty server等待连接.后面代码17处分析*/
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
/*这里获取的url格式为zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo
%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26bind.ip%3D192.168.0.131%26
bind.port%3D20880%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26
qos.port%3D22222%26side%3Dprovider%26timestamp%3D1584018965207&pid=5843&qos.port=22222×tamp=1584018965180 */
URL registryUrl = getRegistryUrl(originInvoker);
//registry provider
//进入ZookeeperRegistryFactory#createRegistry()创建和注册中心连接的zookeeper连接,代码在后面的22处分析
final Registry registry = getRegistry(originInvoker);
final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
//to judge to delay publish whether or not
boolean register = registedProviderUrl.getParameter("register", true);
ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);
if (register) {
//调用FailbackRegistry#register()向zk发出请求,添加节点路径,注册服务提供者,在后面23处分析.
register(registryUrl, registedProviderUrl);
ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
}
// Subscribe the override data
// FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is
// cached key with the name of the service, it causes the subscription information to cover.
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//Ensure that a new exporter instance is returned every time export
return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}
17.导出dubbo协议的invoker.
进入DubboProtocol#export(),这里传入的invoker为ProtocolFilterWrapper包装过的invoker.代码如下:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//取出dubbo协议的url,dubbo:xxx,前面16处有.
URL url = invoker.getUrl();
// export service.
//创建key字串为com.alibaba.dubbo.demo.DemoService:20880
String key = serviceKey(url);
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
exporterMap.put(key, exporter);
//export an stub service for dispatching event
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
if (logger.isWarnEnabled()) {
logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
/* 启动dubbo服务器.DubboProtocol有成员serverMap,key是192.168.0.131:20880格式的地址,value是DubboProtocol#createServer()方法创建的ExchangeServer对象,代码在后面19处分析 */
openServer(url);
//返回DubboExporter
return exporter;
}
18.DubboExporter类,继承自AbstractExporter,代码在前面14处,含有invoker成员.
public class DubboExporter<T> extends AbstractExporter<T> {
//字串为com.alibaba.dubbo.demo.DemoService:20880
private final String key;
//key是上面的key,value是DubboExporter对象本身.在这里做消费端调用过来时,url和接口实现类的映射,导出最核心对象.Exporter里面包含RegistryProtocol.InvokerDelegate->
//DelegateProviderMetaDataInvoker->对象,
private final Map<String, Exporter<?>> exporterMap;
}
19.启动dubbo的ExchangeServer。
private ExchangeServer createServer(URL url) {
...
ExchangeServer server;
try {
/* url 为dubbo://192.168.0.131:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.0.131&bind.port=20880
&channel.readonly.sent=true&codec=dubbo&dubbo=2.0.0&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=5843
&qos.port=22222&side=provider×tamp=1584018965207 格式.
绑定地址.
requestHandler是dubbo协议的请求处理类,是ExchangeHandlerAdapter类型的DubboProtocol匿名内部类的成员变量,代码在后面你的20处.bind()方法进入后面的21处分析.*/
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(Constants.CLIENT_KEY);
if (str != null && str.length() > 0) {
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
20.DubboProtocol的请求处理类
// ExchangeHandlerAdapter类的reply回调方法,代码如下:
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
/* 根据接口的serviceKey从exporterMap成员中找到对应的DubboExporter对象直接调用.serviceKey是com.alibaba.dubbo.demo.DemoService:20880格式,包含了接口的类型.*/
Invoker<?> invoker = getInvoker(channel, inv);
// need to consider backward-compatibility if it's a callback
...
RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
//调用DubboExporter的invoke方法,执行dubbo接口的代理方法.
return invoker.invoke(inv);
}
throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
21.绑定ExchangeServer
进入exchange.Exchangers#bind().传入的url为上面19处的url.代码如下:
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
...
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
/*这里的getExchanger方法是spi动态扩展,获取所有exchange.Exchanger接口的实现类.这里获取到HeaderExchanger类.进入HeaderExchanger#bind()方法,代码如下.*/
return getExchanger(url).bind(url, handler);
}
HeaderExchanger#bind()方法代码如下:
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
/*这里的结构是嵌套的引用关系,HeaderExchangeServer内有Transporters类型的成员server.Transporters类内根据spi动态扩展获取Transporter接口的实现类,
dubbo默认是NettyServer类调用它的bind(),把DecodeHandler传进去.DecodeHandler有ChannelHandler类型的成员指向HeaderExchangeHandler.HeaderExchangeHandler内有
ExchangeHandler类型的成员指向DubboProtocol的请求处理类,即前面20处的ExchangeHandler,回调它的reply()方法,找到DubboExporter的invoke方法调用,如下面代码所示*/
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
处理网络请求的HeaderExchangeHandler#handleRequest()方法.
Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
//创建返回请求的Response对象
Response res = new Response(req.getId(), req.getVersion());
...
// find handler by message class.
Object msg = req.getData();
try {
// handle data.
//调用前面20处的ExchangeHandler,回调它的reply()方法,找到DubboExporter的invoke方法调用
Object result = handler.reply(channel, msg);
res.setStatus(Response.OK);
res.setResult(result);
} catch (Throwable e) {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(e));
}
return res;
}
22.创建和zookeeper的连接.
来自上面的16处,进入ZookeeperRegistryFactory#createRegistry(),创建ZookeeperRegistry对象,连接zk,如下代码所示:
public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) {
...
String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT);
if (!group.startsWith(Constants.PATH_SEPARATOR)) {
group = Constants.PATH_SEPARATOR + group;
}
this.root = group;
//连接zk
zkClient = zookeeperTransporter.connect(url);
//添加zk是否存活的监听器
zkClient.addStateListener(new StateListener() {
public void stateChanged(int state) {
if (state == RECONNECTED) {
try {
recover();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
});
}
23.向zk注册服务提供者.从上面16处进来.进入ZookeeperRegistryFactory#createRegistry()->ZookeeperRegistry#doRegister()
代码如下:
protected void doRegister(URL url) {
try {
/* 向zk请求创建路径.路径为/dubbo/com.alibaba.dubbo.demo.DemoService/providers/dubbo%3A%2F%2F192.168.0.131%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue
%26application%3Ddemo-provider%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D5843%26side%3Dprovider
%26timestamp%3D1584018965207.
格式是 /dubbo/接口全路径/providers/接口信息 */
zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
} catch (Throwable e) {
throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}