前面我们知道通过自定义标签,我们可以定位到相关标签的解析,同时梳理出三个重要的bean:ServiceBean、ReferenceBean、ConfigCenterBean。
通过Servicebean,可以看到ServiceConfig中有我们关注的export方法。
通过export,我们可以看到其暴露服务,又分为本地暴露和远程暴露两种,而暴露之前,会进行配置的检查,然后进行url的组装操作,接着进行exporter,而暴露之前,会进行getInvoker操作。
在getInvoker操作中,首先会进行适配,然后进行动态代理模板生成,生成class文件。
export操作中,进入到RegisterProtocol中,export又分为暴露doLocalExport(originInvoker, providerUrl)—>protocol.export(invokerDelegate)—>DubboProtocol#export(Invoker invoker),完成配置的放入map之后,进行服务器开启openServer(url),进行双重校验创建服务器createServer(url)—> Exchangers.bind(url, requestHandler)—>getExchanger(url).bind(url, handler)—>HanderExchanger#bind(URL url, ExchangeHandler handler)—>Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))—> getTransporter().bind(url, handler)—>NettyTransporter#NettyServer(url, listener)—>NettyServer#doOpen()—>ServerBootstrap# bind(final SocketAddress localAddress),进行配置的和注册、订阅过程。
暴露的过程又是首先进行适配,然后适配之后,进行到dubboProtocol中,进行getInvoker操作。
暴露服务invoker包含两个:一个是暴露在本地injvm中的,一个是暴露到远程的,因此就有两个,但两者都会调用invoker操作:
@SPI("javassist")
public interface ProxyFactory {
//采用的是适配器模式 适配代理的key,获取invoker包含代理和类型和url
@Adaptive({PROXY_KEY})
<T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
我们知道invoker在dubbo中是非常重要的。其底层就是动态代理的思想。思考:invoker是什么,同时其能够做什么,同时暴露服务的过程是什么?
invoker:在dubbo中,Invoker是一个非常重要的模型,在服务提供端和服务引用端都会出现invoker.Dubbo官方文档中对Invoker进行了说明:
invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠拢,或转换成它。它代表一个可执行体,可向它发起invoker调用,它有可能是一个本地的时下,也有可能是一个远程的实现,也有可能一个集群实现。
Invoker是由ProxyFactory创建而来的,Dubbo默认的ProxyFactory实现类是JavassistProxyFactory。其中有jdkProxyFactory、MockProxyFacotry、JavassistProxyFactory、JavassistProxyFactory等
因此我们可以查看javassistProxyFactory:
//默认代理方式 javassist的rpc代理工厂方式
public class JavassistProxyFactory extends AbstractProxyFactory {
//获取invoker
@Override
public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
//为目标类创建wrapper,此时保存的信息生成好了class文件
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
//抽象匿名Invoker类对象,并实现doInvoker方法
return new AbstractProxyInvoker<T>(proxy, type, url) {
//进行invoker
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
//调用wrapper包装类的invokeMethod方法,invokerMethod最终会调用目标方法
//代理对象、方法名称、参数类型、参数
//invoker方法中:对实例的class、hashcode、toString、args进行返回
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
}
javassistProxyFactory中做了这些事:
1.为目标类创建wrapper,此时保存的信息生成好了class文件
2.抽象匿名Invoker类对象,实现doInvoker方法
3.调用wrapper包装类的invokeMethod反复,invokerMethod最终会调用目标方法
4.invokeMethod方法对实例的class、hashcode、toStrring、args进行返回
首先进行getWrapper方法的查看invoker的创建过程
//获取包装对象
//不能包装动态类,如果是动态类,则拿到传入类实例的父类
//如果不是动态类,是Object类,则直接返回包装对象
//否者返回包装的
public static Wrapper getWrapper(Class<?> c) {
while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
{
c = c.getSuperclass();
}
if (c == Object.class) {
return OBJECT_WRAPPER;
}
return WRAPPER_MAP.computeIfAbsent(c, key -> makeWrapper(key));
}
进行模板方法的生成。在这个过程中,我们可以看到获取invoekr需要经历以下步骤:
1.获取包装对象时,首先如果是动态代理类,则返回传入类的父类
2.如果不是动态类,是Object类,则返直接返回包装对象
3.进行合法包装
//进行包装
private static Wrapper makeWrapper(Class<?> c) {
//检查c是不是基本类型,如果是,则抛出异常
if (c.isPrimitive()) {
throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
}
//拿到类的名称、类加载信息、存储的配置信息、invoker信息
String name = c.getName();
ClassLoader cl = ClassUtils.getClassLoader(c);
//c1用于存储setPropertyValue方法代码
StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
//c2用于存储getPropertyValue方法代码
StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
//c3用于存储invokerMethod方法代码
StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
//生成类型转换代码及异常捕获代码,比如:
//DemoService w;try{w = (({DemoService) $1); }}catch(Throwable e){throw new IllegalArgumentException(e);}
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); }");
//pts 用于存储成员变量名和类型
Map<String, Class<?>> pts = new HashMap<>(); //
//ms 用来存储方法描述信息和method实例
Map<String, Method> ms = new LinkedHashMap<>(); //
//mns 为方法名列表
List<String> mns = new ArrayList<>(); // method names.
//dmns 用于存储定义在当前类中的方法的名称
List<String> dmns = new ArrayList<>(); // declaring method names.
/**====================拿到所有公共字段 ==============**/
// get all public field.
for (Field f : c.getFields()) {
//获取名称、类型
String fn = f.getName();
Class<?> ft = f.getType();
// 忽略关键字 static 或 transient 修饰的变量
if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers())) {
continue;
}
c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
//key名称、value 类型
pts.put(fn, ft);
}
//拿到方法
Method[] methods = c.getMethods();
// get all public method.
/**=============拿到所有公共方法 ====================**/
boolean hasMethod = hasMethods(methods);
//检查c中是否包含在当前类中声明的方法
if (hasMethod) {
c3.append(" try{");
for (Method m : methods) {
//ignore Object's method.
//忽略Object中定义的方法
if (m.getDeclaringClass() == Object.class) {
continue;
}
String mn = m.getName();
//生成方法名判断语句
c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
int len = m.getParameterTypes().length;
//生成运行时转入的参数数量和方法参数类表长度判断语句:比如:&& $3.length == 2
c3.append(" && ").append(" $3.length == ").append(len);
boolean override = false;
//检测方法是否存在重载情况,条件为:方法对象不同&&方法名相同
for (Method m2 : methods) {
if (m != m2 && m.getName().equals(m2.getName())) {
override = true;
break;
}
}
//对重载方法进行处理,考虑下面的方法:
//1.void sayHello(Integer,String)
//2.void sayHello(Integer,Integer)
//方法名相同,参数列表长度也相同,因此不能仅通过这两项判断两个方法是否相等
//需要进一步判断方法的参数类型
if (override) {
if (len > 0) {
for (int l = 0; l < len; l++) {
//生成参数类型进行检测代理,比如:&& $3[0].getName().equals("java.lang.Integer")
//&& $3[1].getName().equals("java.lang.String")
c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
.append(m.getParameterTypes()[l].getName()).append("\")");
}
}
}
//添加){,完成方法判断语句,此时生成的代码可能如下(已格式化):
/**
* if ("sayHello".equals($2)
&& $3.length == 2
&& $3[0].getName().equals("java.lang.Integer")
&& $3[1].getName().equals("java.lang.String")) {
*/
c3.append(" ) { ");
//根据返回值类型生成目标方法调用语句
if (m.getReturnType() == Void.TYPE) {
//w.sayHello((java.lang.Integer)$4[0],
//(java.lang.String)$4[1]); return null;
c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
} else {
// return w.sayHello((java.lang.Integer)$4[0],
// (java.lang.String)$4[1]);
c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
}
// 添加 }, 生成的代码形如(已格式化):
// if ("sayHello".equals($2)
// && $3.length == 2
// && $3[0].getName().equals("java.lang.Integer")
// && $3[1].getName().equals("java.lang.String")) {
//
// w.sayHello((java.lang.Integer)$4[0],
// (java.lang.String)$4[1]);
// return null;
// }
c3.append(" }");
//添加方法名到 mns 集合中
mns.add(mn);
// 检测当前方法是否在 c 中被声明的
if (m.getDeclaringClass() == c) {
//如果是,则添加到dmns的list集合中
dmns.add(mn);
}
ms.put(ReflectUtils.getDesc(m), m);
}
//添加异常捕获语句
c3.append(" } catch(Throwable e) { ");
c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
c3.append(" }");
}
// 添加 NoSuchMethodException 异常抛出代码
c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
/**================处理get/set方法 ==============**/
// deal with get/set method.
//处理 get/set方法
Matcher matcher;
for (Map.Entry<String, Method> entry : ms.entrySet()) {
String md = entry.getKey();
Method method = entry.getValue();
// 匹配以 get 开头的方法
if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
// 生成属性判断以及返回语句,示例如下:
// if( $2.equals("name") ) { return ($w).w.getName(); }
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn, method.getReturnType());
// 匹配以 is/has/can 开头的方法
} else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
String pn = propertyName(matcher.group(1));
// 生成属性判断以及返回语句,示例如下:
// if( $2.equals("dream") ) { return ($w).w.hasDream(); }
c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
pts.put(pn, method.getReturnType());
// 匹配以 set 开头的方法
} else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
Class<?> pt = method.getParameterTypes()[0];
String pn = propertyName(matcher.group(1));
// 生成属性判断以及 setter 调用语句,示例如下:
// if($2.equals("name")) {
// w.setName((java.lang.String)$3);
// return;
// }
c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
pts.put(pn, pt);
}
}
// 添加 NoSuchPropertyException 异常抛出代码
c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");
c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" field or setter method in class " + c.getName() + ".\"); }");
/**===================包装类信息 make class=================**/
// make class
long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
//创建类生成器
ClassGenerator cc = ClassGenerator.newInstance(cl);
//设置类名和超类
cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
cc.setSuperClass(Wrapper.class);
//添加默认构造函数
cc.addDefaultConstructor();
//添加字段
cc.addField("public static String[] pns;"); // property name array.
cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
cc.addField("public static String[] mns;"); // all method name array.
cc.addField("public static String[] dmns;"); // declared method name array.
for (int i = 0, len = ms.size(); i < len; i++) {
cc.addField("public static Class[] mts" + i + ";");
}
//添加方法代码
cc.addMethod("public String[] getPropertyNames(){ return pns; }");
cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
cc.addMethod("public String[] getMethodNames(){ return mns; }");
cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
cc.addMethod(c1.toString());
cc.addMethod(c2.toString());
cc.addMethod(c3.toString());
try {
//生成类
Class<?> wc = cc.toClass();
// setup static field.
//设置静态字段值
wc.getField("pts").set(null, pts);
wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
wc.getField("mns").set(null, mns.toArray(new String[0]));
wc.getField("dmns").set(null, dmns.toArray(new String[0]));
int ix = 0;
for (Method m : ms.values()) {
wc.getField("mts" + ix++).set(null, m.getParameterTypes());
}
//场景wrapper实例
return (Wrapper) wc.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
cc.release();
ms.clear();
mns.clear();
dmns.clear();
}
}
生成模板:
1.进行初始化操作:创建c1、c2、c3以及pts、ms、mns等变量,以及向c1、c2、c3中添加方法定义和类型转换代码
2.为 public 级别的字段生成条件判断取值与赋值代码
3.为定义在当前类中的方法生成判断语句,和方法调用语句
4.用于处理getter、setter 以及以 is/has/can 开头的方法。处理方式是通过正则表达式获取方法类型(get/set/is/...),以及属性名
5.为属性名生成判断语句
6.为方法生成调用语句
7.通过 ClassGenerator 为刚刚生成的代码构建 Class 类,并通过反射创建对象。ClassGenerator 是 Dubbo 自己封装的,该类的核心是 toClass() 的重载方法toClass(ClassLoader, ProtectionDomain),该方法通过 javassist 构建 Class。
#invokeMethod(Object instance, String mn, Class>[] types, Object[] args)
进行invokerMethod方法的查看:
public abstract class Wrapper {
//invoker方法
abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
//invoke方法
//invoker方法中:对实例的class、hashcode、toString、args进行返回
@Override
public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException {
if ("getClass".equals(mn)) {
return instance.getClass();
}
if ("hashCode".equals(mn)) {
return instance.hashCode();
}
if ("toString".equals(mn)) {
return instance.toString();
}
if ("equals".equals(mn)) {
if (args.length == 1) {
return instance.equals(args[0]);
}
throw new IllegalArgumentException("Invoke method [" + mn + "] argument number error.");
}
throw new NoSuchMethodException("Method [" + mn + "] not found.");
}
invokerMethod方法中:对实例的class、hashcode、toString、args进行返回。invoker操作完成之后,就可以看服务暴露到本地和服务暴露到远程的操作了。
//暴露服务到本地
//如果url的协议头等于injvm,则说明已经暴露服务到本地了,无需再次暴露
private void exportLocal(URL url) {
URL local = URLBuilder.from(url)
//设置协议头为injvm
.setProtocol(LOCAL_PROTOCOL)
.setHost(LOCALHOST_VALUE)
.setPort(0)
.build();
//重要 Invoker ,关注getInvoker和export方法
//创建invoker,并暴露服务,这里的protocol会在运行时调用InjvmProtocol的export方法
Exporter<?> exporter = PROTOCOL.export(
PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
exporters.add(exporter);
logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
}
//SPI扩展
@SPI("dubbo")
public interface Protocol {
//采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
//本地适配InjvmProtocol
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
}
public class InjvmProtocol extends AbstractProtocol implements Protocol {
//injvm暴露服务的方式 服务暴露到本地
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
//创建InjvmExporter
return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}
}
//构造方法,包含信息:invoker、key、exporterMap
InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
//抽象服务暴露,对其进行校验不为空、invoker、interface、url都不为空
super(invoker);
this.key = key;
this.exporterMap = exporterMap;
//exporterMap中放着key、key与exporterMap
exporterMap.put(key, this);
}
暴露到本地exportLocal:
1.拿到协议头为injvm,同时构建url信息
2.在上面我们已经看到器构建好getInvoker的过程其实是一个采用动态代理,这里采用javassistProxyFactory进行getInvoker。其中会对c进行包装,而包装的过程会成模板方法,也即模板方法的class文件,这个过程重点关注makeWrapper。并拿到相关参数进行返回:class、hashcode、toString、args。
3.暴露到本地:这个过程主要是进行协议url的构建,同时进行协议进行getInvoker,再进行export.采用SPI的扩展方式进行适配协议 InjvmProtocol。而远程采用RegisterProtocol进行适配。主要包括参数key和相关的参数信息,会放入到map中。
由于代码比较多,这里先梳理思路,再看源码
首先进入到export时,先进行registerProtocol,再接着进入到dubboProtocol。这个过程:
1.首先进行采用适配器方式进行匹配协议RegisterProtoco
2获取注册中心 URL ,获取注册的服务提供者URL,获取订阅url,创建订阅服务监听器
3.暴露invoker,远程暴露服务:
1)首先进行通过传入的invoker看是否可以拿到缓存key
2)如果能拿到,则直接访问缓存,创建invoker委托类对象invokerDelegate
3)调用Protocol的export方法暴露服务,这里适配调用dubboProtocol#export方法
4)通过invoekr拿到url信息,拿到url之后,获取服务标识:服务组名、服务名、服务版本号、端口号。类似 demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880.
5)创建dubboExporter,将<key,exporter>键值对放入到缓存中,里面包含了很多的信息,包括url的信息
6)本地存根:通过url获取参数信息:stubEvent、DefaultStub、isCallBackService,拿到本地存根事件方法参数信息
7)启动服务器openServer
(1)从url中获取服务的地址信息(host:port),并将其作为服务器实例的key,用于标识当前的服务器实例,如果是服务器,则采用双重校验锁的方式进行服务器实例的创建serverMap.put(key, createServer(url));
(2)如果服务为空,则创建服务,1.检测是否存在server参数锁表示的Transporter扩展,2.创建服务器实例,3.检测是否支持client参数所表示的Transporter扩展
(3)添加相关参数信息,创建ExchangerServer,也即进行bind操作
(4)获取Exchanger,默认为HeaderExchanger,紧接着调用HeaderExchanger的bind方法创建ExchangerServer实例
(5)进行绑定参照,返回的是消息服务器,这采用HandlerExchanger
(6)首先进行非空校验,校验完之后,进行绑定操作Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
(6)对传入的url和handlers进行非空校验,如果handlers只有一个,则取第一个,如果大于1,则创建channelHandler分发器,获取适配的Transporter实例,并调用实例方法
(7)创建NettyServer,调用父类构造方法,调用父类构造方法,获取ip和端口信息,获取最大可接受连接数,闲置超时时间,调用模板方法doOpen启动服务器
(8)创建boss和worker线程池,创建ServerBoostrap、设置PipelinFactory、绑定到指定的ip和端口上
8)优化序列化
4.注册服务到注册中心
//SPI扩展
@SPI("dubbo")
public interface Protocol {
//采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
//注册协议 暴露服务 远程
/**=================远程暴露,做两件事,一是做服务的远程暴露,二是进行服务注册,在服务中心注册服务================**/
@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
//获取注册中心 URL ,以zookeeper注册中心为例,得到的示例URL如下:
/**
* zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?
* application=demo-provider&dubbo=2.0.2&export=dubbo%3A%2F%2F172.17.48.52%3A20880%2F
* com.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider
*/
URL registryUrl = getRegistryUrl(originInvoker);
// url to export locally
//获取已注册的服务提供者URL ,比如:
/**
* dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&
application=demo-provider&dubbo=2.0.2&generic=false&interface=
com.alibaba.dubbo.demo.DemoService&methods=sayHello
*/
URL providerUrl = getProviderUrl(originInvoker);
// 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.
//获取订阅url
/**
* provider://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?category=c
onfigurators&check=false&anyhost=true&application=demo-provider&
dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello
*/
final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl);
//创建监听器
final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener);
//export invoker
/**=================暴露 invoker ====================**/
//暴露invoker,远程暴露服务 重要
final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl);
/**===============注册到注册中心**+==================**/
// url to registry
final Registry registry = getRegistry(originInvoker);
final URL registeredProviderUrl = getUrlToRegistry(providerUrl, registryUrl);
// decide if we need to delay publish
boolean register = providerUrl.getParameter(REGISTER_KEY, true);
if (register) {
register(registryUrl, registeredProviderUrl);
}
// Deprecated! Subscribe to override rules in 2.6.x or before.
//向注册中心进行订阅Overrider数据
registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
//设置注册服务提供者url、设置获取订阅服务url
exporter.setRegisterUrl(registeredProviderUrl);
exporter.setSubscribeUrl(overrideSubscribeUrl);
//notify暴露
notifyExport(exporter);
//Ensure that a new exporter instance is returned every time export
//确保这是一个每次暴露的都是一个新的暴露服务实例
//创建并返回 DestroyableExporter
return new DestroyableExporter<>(exporter);
}
}
//做服务暴露 localexport
@SuppressWarnings("unchecked")
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) {
//通过invoker拿到key
String key = getCacheKey(originInvoker);
//访问缓存,创建invoker委托类对象
return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> {
Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl);
/**=========================进行暴露包装 ==========================**/
//调用protocol的export方法暴露服务 重要
return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker);
});
}
//采用适配器方式进行匹配暴露服务 采用RegisterProtocol,然后进行dubbo协议 dubboProtocol
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
//远服务暴露 dubbo协议
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();
// export service.
//暴露服务
//获取服务标识,理解成服务坐标也行。由服务组名、服务名、服务版本号以及端口组成。比如:
//demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880
String key = serviceKey(url);
//创建DubboExporter
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
//将 键值对放入缓存中
exporterMap.put(key, exporter);
//export an stub service for dispatching event
//暴露本地存根服务 转发事件
//本地存根相关代码
//获取参数信息:stubEvent、DefaultStub、isCallBackService
Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice) {
//拿到本地存根事假服务参数信息
String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
if (logger.isWarnEnabled()) {
logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
}
}
/**=============启动服务 =============**/
//启动服务器 重要关注
openServer(url);
//优化序列化
optimizeSerialization(url);
return exporter;
}
接着我们看启动服务做了什么
//从url中获取服务的地址信息(host:port)、并将其作为服务器实例的key,用于标识当前的服务器实例
private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client can export a service which's only for server to invoke
boolean isServer = url.getParameter(IS_SERVER_KEY, true);
if (isServer) {
//访问缓存
ProtocolServer server = serverMap.get(key);
//使用双重校验锁
if (server == null) {
synchronized (this) {
/**-============重要 创建服务器实例createServer(url)===============**/
//创建服务器实例
server = serverMap.get(key);
if (server == null) {
serverMap.put(key, createServer(url));
}
}
} else {
// server supports reset, use together with override
//服务器已创建,则根据url中的配置重置服务器
server.reset(url);
}
}
}
//如果服务为空,则创建服务
// 1.检测是否存在server参数锁表示的Transporter扩展
// 2.创建服务器实例
// 3.检测是否支持client参数所表示的Transporter扩展
private ProtocolServer createServer(URL url) {
url = URLBuilder.from(url)
// send readonly event when server closes, it's enabled by default
//当服务器关闭的时候,发送只读事件
.addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString())
// enable heartbeat by default
//添加心跳 默认
.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT))
//添加编码解码器参数
.addParameter(CODEC_KEY, DubboCodec.NAME)
.build();
//拿到server的key和远程默认的服务器netty,获取server参数
String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER);
//通过SPI检测是否存在server参数所代表的Transporter扩展,不存在则抛异常
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
}
ExchangeServer server;
try {
/**-==========================重要 进行bind操作 ====================**/
//创建ExchangerServer 重要
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
//拿到client参数,可以指定netty、mina
str = url.getParameter(CLIENT_KEY);
if (str != null && str.length() > 0) {
//获取所以的Transporter实现类名称集合,比如supportedType=[netty,mina]
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
//检测当前dubbo所支持的Transporter实现类名称列表中,是否包含client所表示的Transporter,若不包含,则抛出异常
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return new DubboProtocolServer(server);
}
如果服务为空,则创建服务
1.检测是否存在server参数锁表示的Transporter扩展
2.创建服务器实例
3.检测是否支持client参数所表示的Transporter扩展
进行服务器绑定
/**=================Exchangers 绑定服务操作 ===================**/
//做服务器绑定操作
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
//获取Exchanger,默认为HeaderExchanger,紧接着调用HeaderExchanger的bind方法创建ExchangerServer实例
//查看HeaderExchangerServer 重要
return getExchanger(url).bind(url, handler);
}
//进行绑定参照,返回的是消息服务器,这里调试采用HandlerExchanger
@Adaptive({Constants.EXCHANGER_KEY})
ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException;
/*****==============重要 绑定bind 消息服务器操作 ==============**/
//返回消息服务器
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
//包含url、handler
//创建HeaderExchangeServer实例,该方法包含了多个逻辑,分别如下:
//1.new HeaderExchangeHeader(handler)
//2.new DecodeHandler(new HeaderExchangeHandler(handler))
//3.Transporters.bind(url,new DecodeHandler(new HanderExchangeHandler(handler)))
//首先进行ChannelHandler非空校验,接着解码handler时进行ChannelHandler非空校验
//校验完之后,进行绑定操作 bind操作 重要
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
//消息服务器
public static RemotingServer bind(URL url, ChannelHandler... handlers) throws RemotingException {
//进行非空校验 url和handler不为空
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handlers == null || handlers.length == 0) {
throw new IllegalArgumentException("handlers == null");
}
ChannelHandler handler;
//如果长度为1,则取第一个
if (handlers.length == 1) {
handler = handlers[0];
} else {
//如果handler的元素长度大于1,则创建channelHandler分发器
handler = new ChannelHandlerDispatcher(handlers);
}
//获取自适应Transporter实例,并调用实例方法
return getTransporter().bind(url, handler);
}
@SPI("netty")
public interface Transporter {
//采用适配器的方式进行适配
@Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException;
}
public class NettyTransporter implements Transporter {
//进行nettyTransporter
@Override
public RemotingServer bind(URL url, ChannelHandler listener) throws RemotingException {
//创建NettyServer
return new NettyServer(url, listener);
}
}
public class NettyServer extends AbstractServer implements RemotingServer {
public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
//调用父类构造方法
super(ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME), ChannelHandlers.wrap(handler, url));
}
//抽象服务 nettyServer
public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
//调用父类构造方法
super(url, handler);
localAddress = getUrl().toInetSocketAddress();
//获取ip和端口信息
String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());
int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());
if (url.getParameter(ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
//设置ip为0.0.0.0
bindIp = ANYHOST_VALUE;
}
bindAddress = new InetSocketAddress(bindIp, bindPort);
//获取最大可接受连接数
this.accepts = url.getParameter(ACCEPTS_KEY, DEFAULT_ACCEPTS);
//闲置超时时间
this.idleTimeout = url.getParameter(IDLE_TIMEOUT_KEY, DEFAULT_IDLE_TIMEOUT);
try {
/**=====================重要 doOpen操作==============**/
//调用模板方法doOpen启动服务器 重点
doOpen();
if (logger.isInfoEnabled()) {
logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());
}
} catch (Throwable t) {
throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
+ " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
}
executor = executorRepository.createExecutorIfAbsent(url);
}
}
public abstract class AbstractServer extends AbstractEndpoint implements RemotingServer {
protected abstract void doOpen() throws Throwable;
}
//NettyServer
public class NettyServer extends AbstractServer implements RemotingServer {
@Override
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
//创建boss和worker线程池
ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
//创建serverBootStrap
bootstrap = new ServerBootstrap(channelFactory);
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
channels = nettyHandler.getChannels();
// https://issues.jboss.org/browse/NETTY-365
// https://issues.jboss.org/browse/NETTY-379
// final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("backlog", getUrl().getPositiveParameter(BACKLOG_KEY, Constants.DEFAULT_BACKLOG));
//设置PipelineFactory
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
ChannelPipeline pipeline = Channels.pipeline();
/*int idleTimeout = getIdleTimeout();
if (idleTimeout > 10000) {
pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
}*/
pipeline.addLast("decoder", adapter.getDecoder());
pipeline.addLast("encoder", adapter.getEncoder());
pipeline.addLast("handler", nettyHandler);
return pipeline;
}
});
// bind
//绑定到指定的ip和端口上
channel = bootstrap.bind(getBindAddress());
}
}
//绑定到指定的ip和端口上
public class ServerBootstrap extends Bootstrap {
public Channel bind(final SocketAddress localAddress) {
//进行非空校验
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
final BlockingQueue<ChannelFuture> futureQueue =
new LinkedBlockingQueue<ChannelFuture>();
ChannelHandler binder = new Binder(localAddress, futureQueue);
ChannelHandler parentHandler = getParentHandler();
ChannelPipeline bossPipeline = pipeline();
//bossPineline
bossPipeline.addLast("binder", binder);
if (parentHandler != null) {
bossPipeline.addLast("userHandler", parentHandler);
}
Channel channel = getFactory().newChannel(bossPipeline);
// Wait until the future is available.
ChannelFuture future = null;
boolean interrupted = false;
do {
try {
future = futureQueue.poll(Integer.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
interrupted = true;
}
} while (future == null);
if (interrupted) {
Thread.currentThread().interrupt();
}
// Wait for the future.
future.awaitUninterruptibly();
if (!future.isSuccess()) {
future.getChannel().close().awaitUninterruptibly();
throw new ChannelException("Failed to bind to: " + localAddress, future.getCause());
}
return channel;
}
}
学习完成服务暴露和getInvoker之后,后续进行服务注册和订阅学习。