Dubbo3.0 引用源码
前提:对应标注了@DubboReference生成的BeanDefinition是
{
"decoratedDefinition": {
"beanDefinition": {
"beanClass": "interface org.apache.dubbo.springboot.demo.DemoService",
"scope": "",
"lazyInit": false,
"autowireMode": 0,
"dependencyCheck": 0,
"autowireCandidate": true,
"primary": false,
"qualifiers": [],
"nonPublicAccessAllowed": true,
"lenientConstructorResolution": true,
"constructorArgumentValues": {
"indexedArgumentValues": {},
"genericArgumentValues": []
},
"propertyValues": [],
"methodOverrides": {
"overrides": []
},
"enforceInitMethod": true,
"enforceDestroyMethod": true,
"synthetic": false,
"role": 0
},
"beanName": "demoService_decorated"
},
"targetType": "class org.apache.dubbo.config.spring.ReferenceBean",
"beanClass": "class org.apache.dubbo.config.spring.ReferenceBean",
"scope": "singleton",
"lazyInit": false,
"autowireMode": 0,
"dependencyCheck": 0,
"autowireCandidate": true,
"primary": false,
"qualifiers": [],
"nonPublicAccessAllowed": true,
"lenientConstructorResolution": true,
"constructorArgumentValues": {
"indexedArgumentValues": {},
"genericArgumentValues": []
},
"propertyValues": [
{
"name": "id",
"value": "demoService",
"optional": true,
"converted": true,
"convertedValue": "demoService"
}
],
"methodOverrides": {
"overrides": []
},
"enforceInitMethod": true,
"enforceDestroyMethod": true,
"synthetic": false,
"role": 0
}
可以看到beanClass是org.apache.dubbo.config.spring.ReferenceBean,而beanName的值是demoService,
下面是构建“demoService”这个bean对象的时候的栈帧信息,
因为ReferenceBean本身是个FactoryBean所以会去调用它的getObject()方法,
进入createLazyProxy()方法,这个方法沿用了Spring的AOP的功能,使用AOP的ProxyFactory和TargetSource,dubbo使用了自定义的TargetSource ,是DubboReferenceLazyInitTargetSource。它什么时候使用的呢?先暂时放一放,知道有这么个东西。
先看看这个createLazyProxy()方法:
private void createLazyProxy() {
//set proxy interfaces
//see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
proxyFactory.addInterface(interfaceClass);
Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
for (Class<?> anInterface : internalInterfaces) {
proxyFactory.addInterface(anInterface);
}
if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
//add service interface
try {
Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
proxyFactory.addInterface(serviceInterface);
} catch (ClassNotFoundException e) {
// generic call maybe without service interface class locally
}
}
//看这里,走到org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)方法
this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}
org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)方法
public Object getProxy(@Nullable ClassLoader classLoader) {
//在dubbo中,createAopProxy()方法会返回org.springframework.aop.framework.JdkDynamicAopProxy对象,它也是JDK动态代理的
//java.lang.reflect.InvocationHandler对象,
//它里面org.springframework.aop.framework.JdkDynamicAopProxy#advised属性就是上面的proxyFactory对象。
//调用到org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法
return createAopProxy().getProxy(classLoader);
}
org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
这个方法的栈帧信息如下:
这里面就要调用到JDK动态代理的方法了,既然说到JDK动态代理,那就不得不说java.lang.reflect.InvocationHandler了,这里的动态代理对象的java.lang.reflect.InvocationHandler就是上面的org.springframework.aop.framework.JdkDynamicAopProxy。
既然是动态代理的对象,肯定会动态生成Class对象,即这里的$Proxy63
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.concurrent.CompletableFuture;
import org.aopalliance.aop.Advice;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.aop.Advisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.core.DecoratingProxy;
public final class $Proxy63 extends Proxy implements DemoService, EchoService, Destroyable, SpringProxy, Advised, DecoratingProxy {
private static Method m1;
private static Method m5;
private static Method m14;
private static Method m18;
private static Method m11;
private static Method m20;
private static Method m8;
private static Method m7;
private static Method m27;
private static Method m22;
private static Method m23;
private static Method m0;
private static Method m9;
private static Method m24;
private static Method m13;
private static Method m12;
private static Method m3;
private static Method m2;
private static Method m29;
private static Method m6;
private static Method m17;
private static Method m30;
private static Method m19;
private static Method m26;
private static Method m28;
private static Method m21;
private static Method m15;
private static Method m4;
private static Method m25;
private static Method m10;
private static Method m16;
public $Proxy63(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final Object $echo(Object var1) throws {
try {
return (Object)super.h.invoke(this, m5, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final boolean isExposeProxy() throws {
try {
return (Boolean)super.h.invoke(this, m14, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void addAdvisor(Advisor var1) throws AopConfigException {
try {
super.h.invoke(this, m18, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final boolean isProxyTargetClass() throws {
try {
return (Boolean)super.h.invoke(this, m11, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void removeAdvisor(int var1) throws AopConfigException {
try {
super.h.invoke(this, m20, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final Class[] getProxiedInterfaces() throws {
try {
return (Class[])super.h.invoke(this, m8, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final TargetSource getTargetSource() throws {
try {
return (TargetSource)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int indexOf(Advisor var1) throws {
try {
return (Integer)super.h.invoke(this, m27, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void addAdvice(int var1, Advice var2) throws AopConfigException {
try {
super.h.invoke(this, m22, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final void addAdvice(Advice var1) throws AopConfigException {
try {
super.h.invoke(this, m23, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean isInterfaceProxied(Class var1) throws {
try {
return (Boolean)super.h.invoke(this, m9, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final boolean removeAdvice(Advice var1) throws {
try {
return (Boolean)super.h.invoke(this, m24, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void setExposeProxy(boolean var1) throws {
try {
super.h.invoke(this, m13, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void setTargetSource(TargetSource var1) throws {
try {
super.h.invoke(this, m12, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String sayHello(String var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class getTargetClass() throws {
try {
return (Class)super.h.invoke(this, m29, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void $destroy() throws {
try {
super.h.invoke(this, m6, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void addAdvisor(int var1, Advisor var2) throws AopConfigException {
try {
super.h.invoke(this, m17, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final Class getDecoratedClass() throws {
try {
return (Class)super.h.invoke(this, m30, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean removeAdvisor(Advisor var1) throws {
try {
return (Boolean)super.h.invoke(this, m19, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int indexOf(Advice var1) throws {
try {
return (Integer)super.h.invoke(this, m26, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final boolean isFrozen() throws {
try {
return (Boolean)super.h.invoke(this, m28, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean replaceAdvisor(Advisor var1, Advisor var2) throws AopConfigException {
try {
return (Boolean)super.h.invoke(this, m21, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final void setPreFiltered(boolean var1) throws {
try {
super.h.invoke(this, m15, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final CompletableFuture sayHelloAsync(String var1) throws {
try {
return (CompletableFuture)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toProxyConfigString() throws {
try {
return (String)super.h.invoke(this, m25, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Advisor[] getAdvisors() throws {
try {
return (Advisor[])super.h.invoke(this, m10, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean isPreFiltered() throws {
try {
return (Boolean)super.h.invoke(this, m16, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m5 = Class.forName("org.apache.dubbo.rpc.service.EchoService").getMethod("$echo", Class.forName("java.lang.Object"));
m14 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isExposeProxy");
m18 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Class.forName("org.springframework.aop.Advisor"));
m11 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isProxyTargetClass");
m20 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Integer.TYPE);
m8 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getProxiedInterfaces");
m7 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetSource");
m27 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.springframework.aop.Advisor"));
m22 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Integer.TYPE, Class.forName("org.aopalliance.aop.Advice"));
m23 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Class.forName("org.aopalliance.aop.Advice"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m9 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isInterfaceProxied", Class.forName("java.lang.Class"));
m24 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvice", Class.forName("org.aopalliance.aop.Advice"));
m13 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setExposeProxy", Boolean.TYPE);
m12 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setTargetSource", Class.forName("org.springframework.aop.TargetSource"));
m3 = Class.forName("org.apache.dubbo.springboot.demo.DemoService").getMethod("sayHello", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m29 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetClass");
m6 = Class.forName("org.apache.dubbo.rpc.service.Destroyable").getMethod("$destroy");
m17 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Integer.TYPE, Class.forName("org.springframework.aop.Advisor"));
m30 = Class.forName("org.springframework.core.DecoratingProxy").getMethod("getDecoratedClass");
m19 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Class.forName("org.springframework.aop.Advisor"));
m26 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.aopalliance.aop.Advice"));
m28 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isFrozen");
m21 = Class.forName("org.springframework.aop.framework.Advised").getMethod("replaceAdvisor", Class.forName("org.springframework.aop.Advisor"), Class.forName("org.springframework.aop.Advisor"));
m15 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setPreFiltered", Boolean.TYPE);
m4 = Class.forName("org.apache.dubbo.springboot.demo.DemoService").getMethod("sayHelloAsync", Class.forName("java.lang.String"));
m25 = Class.forName("org.springframework.aop.framework.Advised").getMethod("toProxyConfigString");
m10 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getAdvisors");
m16 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isPreFiltered");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
因此返回的这个$Proxy63对象就是标注了@DubboReference注解的那个接口,在消费端所以对应的代理对象。它就是在Spring容器中,
beanName为“demoService”的对象。
它的栈帧信息如下:
上面的图里我们提到了,虽然客户端的实际的代理对象已经生成了,但是ref还是null,这个ref就是用来和服务端通信的,它是在哪里生成的呢?在org.apache.dubbo.config.deploy.DefaultModuleDeployer#referServices方法----->
org.apache.dubbo.config.ReferenceConfig#init方法里面去生成的,是DemoServiceDubboProxy0对象,也是个代理对象
这个ref里面就包含了所有的与服务端通信的Invoker对象,也就是包装了NettyClient的Invoker对象,至于ref是怎么生成的,见流程图www.processon.com/diagraming/…
那么到现在,消费端端整个代理对象已经完全的生成结束了,可以拿来用了。根据方法调用,来串一下整体的对象是怎么协作的,不然晕的一逼。
来调用一下:
@SpringBootApplication
@Service
@EnableDubbo
public class ConsumerApplication {
@DubboReference(timeout = 100000)
private DemoService demoService;
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);
ConsumerApplication application = context.getBean(ConsumerApplication.class);
String result = application.doSayHello("world");
System.out.println("result: " + result);
}
public String doSayHello(String name) {
return demoService.sayHello(name);
}
}
代理对象嘛,当然是调用到它的java.lang.reflect.InvocationHandler#invoke方法,这里是org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
//这个targetSource就是前面提了一嘴的DubboReferenceLazyInitTargetSource,就是在这里使用的,这就是
//Spring AOP的用法,那么这个getTarget方法的作用是啥?见下面分析
//getTarget方法获取的是什么呢?其实就是上面的ref对象,也就是DemoServiceDubboProxy0对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//拿这个ref对象去进行服务端的调用,里面就涉及到了netty的通信了
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
上面的getTarget方法最终会调用到org.apache.dubbo.config.spring.ReferenceBean.DubboReferenceLazyInitTargetSource#createObject方法,
//在第一次真正开始调用消费者的时候会走这个方法,把值赋给org.springframework.aop.target.AbstractLazyCreationTargetSource.lazyTarget属性
//
//org.apache.dubbo.config.spring.ReferenceBean.DubboReferenceLazyInitTargetSource#createObject------>
//org.apache.dubbo.config.spring.ReferenceBean#getCallProxy----->org.apache.dubbo.config.ReferenceConfig#get----
//---->去生成dubbo消费端的invoke。这个方法其实也就是去生成ref并赋值给ref的,
//其实呢这个时候其实已经生成了,org.apache.dubbo.config.ReferenceConfig#get方法在org.apache.dubbo.config.deploy.DefaultModuleDeployer#referServices方法中已经调用了,也就是已经生成了dubbo消费端的invoke也就是MigrationInvoker对象
@Override
protected Object createObject() throws Exception {
System.out.println("ref创建开始"+Thread.currentThread());
return getCallProxy();
}
看到这里,可以总结一下,Dubbo的消费端对象,主要是由两个代理对象构成,1个是$Proxy63代理对象,第2个是DemoServiceDubboProxy0,$Proxy63是我们业务上的消费端和服务端都用的Dubbo的接口所对应的代理对象,如例子中的org.apache.dubbo.springboot.demo.DemoService,这个代理对象就是上面的$Proxy63,是利用JDK的动态代理生成的。
而DemoServiceDubboProxy0是Dubbo自己模拟JDK动态代理,自己实现了一套动态生成Class内容的一个代理类,lazyTarget其实就是上面讲的ref,具体的代码如下:
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* org.apache.dubbo.springboot.demo.DemoService
*/
package org.apache.dubbo.springboot.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.springboot.demo.DemoService;
public class DemoServiceDubboProxy0 implements ClassGenerator.DC,DemoService,EchoService,Destroyable {
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String string) {
Object[] objectArray = new Object[]{string};
Object object = this.handler.invoke(this, methods[0], objectArray);
return (String)object;
}
public CompletableFuture sayHelloAsync(String string) {
Object[] objectArray = new Object[]{string};
Object object = this.handler.invoke(this, methods[1], objectArray);
return (CompletableFuture)object;
}
@Override
public Object $echo(Object object) {
Object[] objectArray = new Object[]{object};
Object object2 = this.handler.invoke(this, methods[2], objectArray);
return object2;
}
@Override
public void $destroy() {
Object[] objectArray = new Object[]{};
Object object = this.handler.invoke(this, methods[3], objectArray);
}
public DemoServiceDubboProxy0() {
}
public DemoServiceDubboProxy0(InvocationHandler invocationHandler) {
this.handler = invocationHandler;
}
}
动态生成Class后,在org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getProxy方法里面,利用反射去生成DemoServiceDubboProxy0对象。
public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
try {
//看这里,invoker是org.apache.dubbo.registry.client.migration.MigrationInvoker
return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
} catch (Throwable fromJavassist) {
// try fall back to JDK proxy factory
try {
T proxy = jdkProxyFactory.getProxy(invoker, interfaces);
logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. " +
"Interfaces: " + Arrays.toString(interfaces), fromJavassist);
return proxy;
} catch (Throwable fromJdk) {
logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + Arrays.toString(interfaces) + " Javassist Error.", fromJavassist);
logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
"Interfaces: " + Arrays.toString(interfaces) + " JDK Error.", fromJdk);
throw fromJavassist;
}
}
}
既然是动态代理对象,主要的逻辑也是在java.lang.reflect.InvocationHandler,这里的是org.apache.dubbo.rpc.proxy.InvokerInvocationHandler
public class InvokerInvocationHandler implements InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);
//invoker是org.apache.dubbo.registry.client.migration.MigrationInvoker
private final Invoker<?> invoker;
private final ServiceModel serviceModel;
private final String protocolServiceKey;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
URL url = invoker.getUrl();
this.protocolServiceKey = url.getProtocolServiceKey();
this.serviceModel = url.getServiceModel();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(invoker, args);
}
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
if ("toString".equals(methodName)) {
return invoker.toString();
} else if ("$destroy".equals(methodName)) {
invoker.destroy();
return null;
} else if ("hashCode".equals(methodName)) {
return invoker.hashCode();
}
} else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
return invoker.equals(args[0]);
}
RpcInvocation rpcInvocation = new RpcInvocation(serviceModel, method.getName(), invoker.getInterface().getName(), protocolServiceKey, method.getParameterTypes(), args);
if (serviceModel instanceof ConsumerModel) {
rpcInvocation.put(Constants.CONSUMER_MODEL, serviceModel);
rpcInvocation.put(Constants.METHOD_MODEL, ((ConsumerModel) serviceModel).getMethodModel(method));
}
//走这里
return InvocationUtil.invoke(invoker, rpcInvocation);
}
}
然后调用到org.apache.dubbo.registry.client.migration.MigrationInvoker#invoke方法,然后调用到org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke,
下面的调用过程虽然是根据2.7的源码画的,但是大差不差的调用流程参考一下:
org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke------>
最终会调用到org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke方法,具体看看这个方法,
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment(PATH_KEY, getUrl().getPath());
inv.setAttachment(VERSION_KEY, version);
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
int timeout = calculateTimeout(invocation, methodName);
if (timeout <= 0) {
return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
"No time left for making the following call: " + invocation.getServiceName() + "."
+ invocation.getMethodName() + ", terminate directly."), invocation);
}
invocation.setAttachment(TIMEOUT_KEY, timeout);
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
return AsyncRpcResult.newDefaultAsyncResult(invocation);
} else {
//构造一个线程池
ExecutorService executor = getCallbackExecutor(getUrl(), inv);
//发送请求,请求到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法
CompletableFuture<AppResponse> appResponseFuture =
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
// save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
FutureContext.getContext().setCompatibleFuture(appResponseFuture);
//同步转异步
AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
result.setExecutor(executor);
return result;
}
} 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);
}
}
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)代码:
public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
// create request.
//将请求参数包装成Request
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
req.setData(request);
//这里很重要,先构造CompletableFuture类型的对象DefaultFuture
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
try {
//然后利用netty发送请求
channel.send(req);
} catch (RemotingException e) {
future.cancel();
throw e;
}
//然后直接返回future
return future;
}
public static DefaultFuture newFuture(Channel channel, Request request, int timeout, ExecutorService executor) {
//构建一个DefaultFuture对象,服务端返回到结果就是会放到这里里面
final DefaultFuture future = new DefaultFuture(channel, request, timeout);
future.setExecutor(executor);
// ThreadlessExecutor needs to hold the waiting future in case of circuit return.
if (executor instanceof ThreadlessExecutor) {
((ThreadlessExecutor) executor).setWaitingFuture(future);
}
// timeout check
//在这里启动dubbo到超时机制,就是个定时任务
timeoutCheck(future);
return future;
}
private DefaultFuture(Channel channel, Request request, int timeout) {
this.channel = channel;
this.request = request;
//每次请求到唯一标识,就是接收到服务端请求到时候,用它从org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES里面根据这个id获取DefaultFuture对象,然后把结果放入到DefaultFuture里面
this.id = request.getId();
this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
// put into waiting map.
//把创建的放入到org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES,它是个全局对象
FUTURES.put(id, this);
CHANNELS.put(id, channel);
}
DefaultFuture对象构造完了,现在回到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法,该方法构造完DefaultFuture对象后,然后利用netty给服务端发请求后,就直接返回
future这个对象了,存放请求结果的future和发送请求是分异步发送的,没有任何关系,那么怎么拿到服务端返回的结果的呢????? 重点就在两个地方了,1个就是DefaultFuture里面的id,第2个就是org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES
那么先看看,直接返回的这个future对象有什么作用呢?先返回到org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvok方法,看这行代码:thenApply(obj -> (AppResponse) obj)
ompletableFuture<AppResponse> appResponseFuture =
currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
这个thenApply方法方法有啥用呢?它返回到也是一个CompletableFuture对象,相当于把DefaultFuture和这个CompletableFuture对象绑定了在一起,也就是currentClient.request(inv, timeout, executor)返回到对象和appResponseFuture绑定了在一起了,即DefaultFuture有值了那么appResponseFuture也就有值了。那么赋值的动作具体在哪里呢?????回到方法org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke,里面有行代码waitForResultIfSync(asyncResult, invocation);
这里的asyncResult里面包装了上面的appResponseFuture,以及executor,分别放在了org.apache.dubbo.rpc.AsyncRpcResult#responseFuture和org.apache.dubbo.rpc.AsyncRpcResult#executor两个属性里面。
private void waitForResultIfSync(AsyncRpcResult asyncResult, RpcInvocation invocation) {
if (InvokeMode.SYNC != invocation.getInvokeMode()) {
return;
}
try {
/*
* NOTICE!
* must call {@link java.util.concurrent.CompletableFuture#get(long, TimeUnit)} because
* {@link java.util.concurrent.CompletableFuture#get()} was proved to have serious performance drop.
*/
Object timeout = invocation.getObjectAttachmentWithoutConvert(TIMEOUT_KEY);
if (timeout instanceof Integer) {
//看这里,调用到org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit)方法
asyncResult.get((Integer) timeout, TimeUnit.MILLISECONDS);
} else {
asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RpcException("Interrupted unexpectedly while waiting for remote result to return! method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (ExecutionException e) {
Throwable rootCause = e.getCause();
if (rootCause instanceof TimeoutException) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else if (rootCause instanceof RemotingException) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else {
throw new RpcException(RpcException.UNKNOWN_EXCEPTION, "Fail to invoke remote method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
} catch (java.util.concurrent.TimeoutException e) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " +
invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (Throwable e) {
throw new RpcException(e.getMessage(), e);
}
}
org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit):
public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (executor != null && executor instanceof ThreadlessExecutor) {
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
//看这里,最终调用到org.apache.dubbo.remoting.exchange.support.DefaultFuture.doReceived方法,将服务端的返回结果设置到发送请求时候
//调用的的那个方法org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(java.lang.Object, int, java.util.concurrent.ExecutorService)
//中生成的DefaultFuture对象中
threadlessExecutor.waitAndDrain();
}
//因此,responseFuture其实就是org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法的
//那个DefaultFuture对象,上面已经给这个DefaultFuture设置了响应结果,因此responseFuture也就有值了
return responseFuture.get(timeout, unit);
org.apache.dubbo.common.threadpool.ThreadlessExecutor#waitAndDrain:
public void waitAndDrain() throws InterruptedException {
/**
* Usually, {@link #waitAndDrain()} will only get called once. It blocks for the response for the first time,
* once the response (the task) reached and being executed waitAndDrain will return, the whole request process
* then finishes. Subsequent calls on {@link #waitAndDrain()} (if there're any) should return immediately.
*
* There's no need to worry that {@link #finished} is not thread-safe. Checking and updating of
* 'finished' only appear in waitAndDrain, since waitAndDrain is binding to one RPC call (one thread), the call
* of it is totally sequential.
*/
if (isFinished()) {
return;
}
Runnable runnable;
try {
//看这里
runnable = queue.take();
} catch (InterruptedException e) {
setWaiting(false);
throw e;
}
synchronized (lock) {
setWaiting(false);
runnable.run();
}
runnable = queue.poll();
while (runnable != null) {
runnable.run();
runnable = queue.poll();
}
// mark the status of ThreadlessExecutor as finished.
setFinished(true);
}
看runnable = queue.take();这行代码,其实就是从queue里面去拿任务去执行,那么任务是从哪里放进去的呢????
这就要说到服务端的响应了,当服务端通过netty写回响应的时候,任务就是从org.apache.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.received里面放入的,也就是服务端的netty响应给客户端的netty的时候,走netty 的Handler来放入的ChannelEventRunnable对象。注意,往queue里面放的时候,是netty自己的线程哦,是异步哦,因为异步,所以会在take方法阻塞,直到netty往这个队列里面放任务哦。
所以DefaultFuture有值了那么appResponseFuture绑定的值是还是要看org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run方法,具体的注释看自己的源码注释gitee.com/shylovejay/…
最终调用到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse方法,
static void handleResponse(Channel channel, Response response) throws RemotingException {
if (response != null && !response.isHeartbeat()) {
//看这里,org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean)
DefaultFuture.received(channel, response);
}
}
org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean):
public static void received(Channel channel, Response response, boolean timeout) {
try {
//看到没,从FUTURES这个全局变量里面根据id获取对应的DefaultFuture对象,这个对象就是在请求的时候
// 在org.apache.dubbo.remoting.exchange.support.DefaultFuture.DefaultFuture里面放入的
DefaultFuture future = FUTURES.remove(response.getId());
if (future != null) {
//将判断是否超实的定时器关闭
Timeout t = future.timeoutCheckTask;
if (!timeout) {
// decrease Time
t.cancel();
}
//看这里 调用到org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived
future.doReceived(response);
} else {
logger.warn(PROTOCOL_TIMEOUT_SERVER, "", "", "The timeout response finally returned at "
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
+ ", response status is " + response.getStatus()
+ (channel == null ? "" : ", channel: " + channel.getLocalAddress()
+ " -> " + channel.getRemoteAddress()) + ", please check provider side for detailed result.");
}
} finally {
CHANNELS.remove(response.getId());
}
}
org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived:
private void doReceived(Response res) {
if (res == null) {
throw new IllegalStateException("response cannot be null");
}
if (res.getStatus() == Response.OK) {
//将解码的好的服务端的返回结果设置到该DefaultFuture对象中,具体代码是java.util.concurrent.CompletableFuture.completeValue这个方法
//complete里面还有一行代码 postComplete();,这行很重要,
//它作用就是DefaultFuture里面已经有值了,然而在CompletableFuture<AppResponse> appResponseFuture =
// currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);代码中
//DefaultFuture里面的有包装了一个CompletableFuture,而这个CompletableFuture对象就是上面的appResponseFuture,它
//在org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke方法中被包装了在AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);对象中。
//因此,DefaultFuture里面已经有值,那么appResponseFuture里就有值了,那么从org.apache.dubbo.rpc.AsyncRpcResult.get(long, java.util.concurrent.TimeUnit)方法的
//responseFuture.get(timeout, unit);代码中就能拿到值了
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()));
}
// the result is returning, but the caller thread may still wait
// to avoid endless waiting for whatever reason, notify caller thread to return.
if (executor != null && executor instanceof ThreadlessExecutor) {
ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
if (threadlessExecutor.isWaiting()) {
threadlessExecutor.notifyReturn(new IllegalStateException("The result has returned, but the biz thread is still waiting" +
" which is not an expected state, interrupt the thread manually by returning an exception."));
}
}
}
现在回到方法org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit),结果拿到了,那么threadlessExecutor.waitAndDrain();也就结束阻塞了。responseFuture.get(timeout, unit);也就拿到了最终的服务端返回的结果。
拿到结果就万事大吉了吗?当然没有,毕竟服务端要是抛出异常了,我们也要抛出来,所有对结果还是要做进一步的处理的。
直接返回到org.apache.dubbo.rpc.proxy.InvocationUtil#invoke代码,回到return invoker.invoke(rpcInvocation).recreate();这行代码.
public Object recreate() throws Throwable {
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
if (InvokeMode.FUTURE == rpcInvocation.getInvokeMode()) {
return RpcContext.getClientAttachment().getFuture();
} else if (InvokeMode.ASYNC == rpcInvocation.getInvokeMode()) {
return createDefaultValue(invocation).recreate();
}
//调用到org.apache.dubbo.rpc.AppResponse.recreate方法
return getAppResponse().recreate();
}
org.apache.dubbo.rpc.AppResponse#recreate:
public Object recreate() throws Throwable {
//如果exception不为null,说明服务端抛出了业务异常了,所以要像本地调用一样的将这个异常抛出
//exception和result的值是在org.apache.dubbo.remoting.transport.DecodeHandler.decode方法中解码出来的
if (exception != null) {
// fix issue#619
try {
Object stackTrace = exception.getStackTrace();
if (stackTrace == null) {
exception.setStackTrace(new StackTraceElement[0]);
}
} catch (Exception e) {
// ignore
}
throw exception;
}
//如果没有异常,将结果返回过去
return result;
}
好了,结束。
Dubbo3.0的注册中心监听
消费者:
消费者是一定要一直监听注册中心来实时感知提供者配置的变化的,包括提供者的下线和上线的,从而实时改变自己的调用策略,调用参数等等。
那么监听注册中心哪里呢?不同的注册中心实现不同,但是统一的入口是在org.apache.dubbo.registry.integration.RegistryProtocol#doCreateInvoker方法。
protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
// DynamicDirectory directory动态服务目录有两种:RegistryDirectory和ServiceDiscoveryRegistryDirectory
// RegistryDirectory用来记录和监听接口级服务提供者地址
// ServiceDiscoveryRegistryDirectory用来记录和监听应用级服务提供者地址
// Registry registry也有两种:ListenerRegistryWrapper,它里面包装了ZookeeperRegistry、NacosRegistry这种注册中心的,继承了FailbackRegistry,和ServiceDiscoveryRegistry,也继承了FailbackRegistry
// 一个DynamicDirectory中包含一个Registry,Registry用来同步远程注册中心的数据,所以需要监听数据的变化
directory.setRegistry(registry);
directory.setProtocol(protocol);
// all attributes of REFER_KEY
//获取消费端的参数{side=consumer, register.ip=192.168.3.12, release=3.1.2-SNAPSHOT, methods=sayHello, dubbo=2.0.2, pid=17876, interface=org.apache.dubbo.springboot.demo.DemoService, qos.enable=true, unloadClusterRelated=false, application=dubbo-springboot-demo-consumer, background=false, sticky=false, timestamp=1669280017621}
Map<String, String> parameters = new HashMap<>(directory.getConsumerUrl().getParameters());
//构造出要注册到注册中心的consumer的url,consumer://192.168.3.12/org.apache.dubbo.springboot.demo.DemoService?application=dubbo-springboot-demo-consumer&background=false&dubbo=2.0.2&interface=org.apache.dubbo.springboot.demo.DemoService&methods=sayHello&pid=17876&qos.enable=true&release=3.1.2-SNAPSHOT&side=consumer&sticky=false×tamp=1669280017621&unloadClusterRelated=false
URL urlToRegistry = new ServiceConfigURL(
parameters.get(PROTOCOL_KEY) == null ? CONSUMER : parameters.get(PROTOCOL_KEY),
parameters.remove(REGISTER_IP_KEY),
0,
getPath(parameters, type),
parameters
);
urlToRegistry = urlToRegistry.setScopeModel(directory.getConsumerUrl().getScopeModel());
urlToRegistry = urlToRegistry.setServiceModel(directory.getConsumerUrl().getServiceModel());
if (directory.isShouldRegister()) {
directory.setRegisteredConsumerUrl(urlToRegistry);
//对于zk,将consumer对应的url注册到zk,对应的节点是/dubbo/org.apache.dubbo.springboot.demo.DemoService/consumers/consumer%3A%2F%2F192.168.3.12%2Forg.apache.dubbo.springboot.demo.DemoService%3Fapplication%3Ddubbo-springboot-demo-consumer%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26interface%3Dorg.apache.dubbo.springboot.demo.DemoService%26methods%3DsayHello%26pid%3D17876%26qos.enable%3Dtrue%26release%3D3.1.2-SNAPSHOT%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1669280017621%26unloadClusterRelated%3Dfalse
//对于nacos,调用到org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper#registerInstance,注册到
//分组DEFAULT_GROUP,服务名为consumers:org.apache.dubbo.springboot.demo.DemoService::
registry.register(directory.getRegisteredConsumerUrl());
}
directory.buildRouterChain(urlToRegistry);
// 监听相应的注册中心目录,触发生成Invoker
//在这里启动netty客户端的
//toSubscribeUrl(urlToRegistry)方法给urlToRegistry添加了category=providers,configurators,routers参数
// consumer://192.168.3.12/org.apache.dubbo.springboot.demo.DemoService?application=dubbo-springboot-demo-consumer&background=false&category=providers,configurators,routers&dubbo=2.0.2&interface=org.apache.dubbo.springboot.demo.DemoService&methods=sayHello&pid=17876&qos.enable=true&release=3.1.2-SNAPSHOT&side=consumer&sticky=false×tamp=1669280017621&unloadClusterRelated=false
//对于zk,监听的路径是/dubbo/org.apache.dubbo.springboot.demo.DemoService/providers
// /dubbo/org.apache.dubbo.springboot.demo.DemoService/configurators
// /dubbo/org.apache.dubbo.springboot.demo.DemoService/routers
//对于nacos,监听的是DEFAULT_GROUP下面的名字为providers:org.apache.dubbo.springboot.demo.DemoService::, providers:org.apache.dubbo.springboot.demo.DemoService这两个服务
directory.subscribe(toSubscribeUrl(urlToRegistry));
//调用到org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper.join方法
return (ClusterInvoker<T>) cluster.join(directory, true);
}
directory.subscribe(toSubscribeUrl(urlToRegistry));这行代码就是去注册中心监听提供者的动态了。
nacos:
对于nacos,监听的代码最终会调用到com.alibaba.nacos.client.naming.NacosNamingService#subscribe(java.lang.String, java.lang.String, java.util.List<java.lang.String>, com.alibaba.nacos.api.naming.listener.EventListener)方法。
public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
throws NacosException {
if (null == listener) {
return;
}
String clusterString = StringUtils.join(clusters, ",");
//看这里,先注册监听器,注意,这个listener里面就包装了我们的RegistryDirectory
//将这个listter对象@11615,放入到com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#listenerMap这个Map中,key是DEFAULT_GROUP@@providers:org.apache.dubbo.springboot.demo.DemoService::
changeNotifier.registerListener(groupName, serviceName, clusterString, listener);
//看这里
clientProxy.subscribe(serviceName, groupName, clusterString);
}
接着看com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate#subscribe方法:
public ServiceInfo subscribe(String serviceName, String groupName, String clusters) throws NacosException {
NAMING_LOGGER.info("[SUBSCRIBE-SERVICE] service:{}, group:{}, clusters:{} ", serviceName, groupName, clusters);
String serviceNameWithGroup = NamingUtils.getGroupedName(serviceName, groupName);
String serviceKey = ServiceInfo.getKey(serviceNameWithGroup, clusters);
//看这行代码
serviceInfoUpdateService.scheduleUpdateIfAbsent(serviceName, groupName, clusters);
ServiceInfo result = serviceInfoHolder.getServiceInfoMap().get(serviceKey);
if (null == result || !isSubscribed(serviceName, groupName, clusters)) {
result = grpcClientProxy.subscribe(serviceName, groupName, clusters);
}
serviceInfoHolder.processServiceInfo(result);
return result;
}
com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService#scheduleUpdateIfAbsent方法:
public void scheduleUpdateIfAbsent(String serviceName, String groupName, String clusters) {
if (!asyncQuerySubscribeService) {
return;
}
String serviceKey = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
if (futureMap.get(serviceKey) != null) {
return;
}
synchronized (futureMap) {
if (futureMap.get(serviceKey) != null) {
return;
}
//看这里的UpdateTask,它是个Runnable,addTask方法会启动这个Runnable,直接看它的run方法
ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, groupName, clusters));
futureMap.put(serviceKey, future);
}
}
com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService.UpdateTask#run方法:
public void run() {
long delayTime = DEFAULT_DELAY;
try {
if (!changeNotifier.isSubscribed(groupName, serviceName, clusters) && !futureMap.containsKey(
serviceKey)) {
NAMING_LOGGER.info("update task is stopped, service:{}, clusters:{}", groupedServiceName, clusters);
isCancel = true;
return;
}
ServiceInfo serviceObj = serviceInfoHolder.getServiceInfoMap().get(serviceKey);
if (serviceObj == null) {
serviceObj = namingClientProxy.queryInstancesOfService(serviceName, groupName, clusters, 0, false);
serviceInfoHolder.processServiceInfo(serviceObj);
lastRefTime = serviceObj.getLastRefTime();
return;
}
if (serviceObj.getLastRefTime() <= lastRefTime) {
serviceObj = namingClientProxy.queryInstancesOfService(serviceName, groupName, clusters, 0, false);
//看这里
serviceInfoHolder.processServiceInfo(serviceObj);
}
lastRefTime = serviceObj.getLastRefTime();
if (CollectionUtils.isEmpty(serviceObj.getHosts())) {
incFailCount();
return;
}
// TODO multiple time can be configured.
delayTime = serviceObj.getCacheMillis() * DEFAULT_UPDATE_CACHE_TIME_MULTIPLE;
resetFailCount();
} catch (NacosException e) {
handleNacosException(e);
} catch (Throwable e) {
handleUnknownException(e);
} finally {
if (!isCancel) {
executor.schedule(this, Math.min(delayTime << failCount, DEFAULT_DELAY * 60),
TimeUnit.MILLISECONDS);
}
}
}
com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#processServiceInfo(com.alibaba.nacos.api.naming.pojo.ServiceInfo)方法:
public ServiceInfo processServiceInfo(ServiceInfo serviceInfo) {
String serviceKey = serviceInfo.getKey();
if (serviceKey == null) {
return null;
}
ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
if (isEmptyOrErrorPush(serviceInfo)) {
//empty or error push, just ignore
return oldService;
}
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
boolean changed = isChangedServiceInfo(oldService, serviceInfo);
if (StringUtils.isBlank(serviceInfo.getJsonFromServer())) {
serviceInfo.setJsonFromServer(JacksonUtils.toJson(serviceInfo));
}
MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());
if (changed) {//与本地缓存的提供者的配置相比,如果注册中心的提供者的配置发生变化,则发布一个InstancesChangeEvent事件
NAMING_LOGGER.info("current ips:({}) service: {} -> {}", serviceInfo.ipCount(), serviceInfo.getKey(),
JacksonUtils.toJson(serviceInfo.getHosts()));
//发布一个InstancesChangeEvent事件
NotifyCenter.publishEvent(new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
serviceInfo.getClusters(), serviceInfo.getHosts()));
DiskCache.write(serviceInfo, cacheDir);
}
return serviceInfo;
}
最终调用到com.alibaba.nacos.common.notify.DefaultPublisher#publish方法:
注意com.alibaba.nacos.common.notify.DefaultPublisher其实是个Runnable
public boolean publish(Event event) {
checkIsStart();
//发布事件,其实就是放入到,com.alibaba.nacos.common.notify.DefaultPublisher#queue这个队列中
//那么既然有放入到,又是哪里拿出来的呢?
boolean success = this.queue.offer(event);
if (!success) {
LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);
receiveEvent(event);
return true;
}
return true;
}
com.alibaba.nacos.common.notify.DefaultPublisher既然是个Runnable,那么肯定有个地方会启动,在哪里呢??
其实就是在com.alibaba.nacos.common.notify.DefaultPublisher#init方法中,直接启动的。
public void init(Class<? extends Event> type, int bufferSize) {
setDaemon(true);
setName("nacos.publisher-" + type.getName());
this.eventType = type;
this.queueMaxSize = bufferSize;
this.queue = new ArrayBlockingQueue<>(bufferSize);
start();
}
现在看看怎么从里面取到任务去执行的,
public void run() {
openEventHandler();
}
void openEventHandler() {
try {
// This variable is defined to resolve the problem which message overstock in the queue.
int waitTimes = 60;
// To ensure that messages are not lost, enable EventHandler when
// waiting for the first Subscriber to register
for (; ; ) {
if (shutdown || hasSubscriber() || waitTimes <= 0) {
break;
}
ThreadUtils.sleep(1000L);
waitTimes--;
}
for (; ; ) {
if (shutdown) {
break;
}
//这就首尾呼应上了,从里面取得InstancesChangeEvent事件
final Event event = queue.take();
//开始处理
receiveEvent(event);
UPDATER.compareAndSet(this, lastEventSequence, Math.max(lastEventSequence, event.sequence()));
}
} catch (Throwable ex) {
LOGGER.error("Event listener exception : ", ex);
}
}
调用com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#onEvent方法,
public void onEvent(InstancesChangeEvent event) {
String key = ServiceInfo
.getKey(NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName()), event.getClusters());
//这又首尾呼应上了,从com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#listenerMap获取监听者,看到没,他就是@11615那个对象
//key是DEFAULT_GROUP@@providers:org.apache.dubbo.springboot.demo.DemoService::
ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);
if (CollectionUtils.isEmpty(eventListeners)) {
return;
}
for (final EventListener listener : eventListeners) {
final com.alibaba.nacos.api.naming.listener.Event namingEvent = transferToNamingEvent(event);
if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {
((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(namingEvent));
} else {
//调用到org.apache.dubbo.registry.nacos.NacosRegistry.RegistryChildListenerImpl#onEvent方法
//它既是@11615那个对象
listener.onEvent(namingEvent);
}
}
}
最终会调用到org.apache.dubbo.registry.integration.RegistryDirectory#notify方法,去重新生成消费端端invoker对象,
public synchronized void notify(List<URL> urls) {
if (isDestroyed()) {
return;
}
Map<String, List<URL>> categoryUrls = urls.stream()
.filter(Objects::nonNull)
.filter(this::isValidCategory)
.filter(this::isNotCompatibleFor26x)
.collect(Collectors.groupingBy(this::judgeCategory));
List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY, Collections.emptyList());
this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);
List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY, Collections.emptyList());
toRouters(routerURLs).ifPresent(this::addRouters);
// providers
List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());
// 3.x added for extend URL address
ExtensionLoader<AddressListener> addressListenerExtensionLoader = getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);
List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);
if (supportedListeners != null && !supportedListeners.isEmpty()) {
for (AddressListener addressListener : supportedListeners) {
providerURLs = addressListener.notify(providerURLs, getConsumerUrl(), this);
}
}
//重新去生成invoker
refreshOverrideAndInvoker(providerURLs);
}