前言:或许很多人会使用dubbo,但是阅读源码将使我们更加了解它,以及在未来对它进行改进优化。我就先把flag立在这里了,接下来这阵子将会深入源码进行学习和优化。做为一个要使用dubbo的程序员,必须需要深入理解它,因为dubbo已经停止了维护。
一,dubbo的分层架构
因为是第一篇,这些基础的东西需要先了解,对后面阅读源码也有好处,只做简单介绍,详细的可以看dubbo的官方手册。
1,Service层:该层与实际的业务内容相关,根据服务提供方和消费方提供对应的接口和实现
2,Config层:负责解析spring的配置文件,主要涉及ServiceConfig和ReferenceConfig
3,Proxy层:服务接口透明代理,生成服务的客户端Stub和服务端Skeleton,已ServiceProxy为中心,扩展接口为ProxyFactory
4,Registry层:封装服务地址的注册和发现,以服务URL为中心,扩展为RegistryFactory,Registry和RegistryService,可能没有服务注册中心,此时服务提供方直接暴露服务。
5,Cluster层:封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster,Directory,Router和LoadBalance,将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
6,Monitor层:RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory,Monitor和MonitorService
7,Protocol层:封装RPC调用,以Invocation和Result为中心,扩展接口为Protocol,Invoker和Exporter。Protocol是服务域,是Invoker暴露和引用的主功能入口,负责Invoker的生命周期管理。Invoker是实体域,是Dubbo的核心模型,其他模型都向他靠拢或者转换为它,它代表一个可执行体,可以向它发起Invoke调用,它有可能是一个本地实现或者一个远程的实现或者一个集群的实现
8,Exchange层:封装请求响应模型,同步转异步,以Request和Response为中心,扩展接口为Exchanger,ExchangeChannel,ExchangeClient和ExchangeServer。
9,Transport层:抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel,Transport,Client,Server和Codec。
10,Serialize层:可复用的一些工具,扩展接口为Serialization,ObjectInput,ObjectOutput和ThreadPool。
二,代码模块划分
1,dubbo-common 公共逻辑模块,包括Util类和通用模型。
2,dubbo-remoting 远程通讯模块,相当于Dubbo协议的实现,如果RPC用RMI协议则不需要使用此包。
3,dubbo-rpc 远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。
4,dubbo-cluster 集群模块,将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。
5,dubbo-registry 注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
dubbo-monitor 监控模块,统计服务调用次数,调用时间的,调用链跟踪的服务。
6,dubbo-config 配置模块,是Dubbo对外的API,用户通过Config使用Dubbo,隐藏Dubbo所有细节。
7,dubbo-container 容器模块,是一个Standlone的容器,以简单的Main加载Spring启动,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务
三,dubbo-config模块的代码阅读
1,beanutil包(主要是对class的一些定义和对反射的封装)
1.1 JavaBeanAccessor
(这个类相对容易理解,看定义和方法就可以了)
public enum JavaBeanAccessor {
/** Field accessor. */
FIELD,
/** Method accessor.*/
METHOD,
/** Method prefer to field. */
ALL;
public static boolean isAccessByMethod(JavaBeanAccessor accessor) {
return METHOD.equals(accessor) || ALL.equals(accessor);
}
public static boolean isAccessByField(JavaBeanAccessor accessor) {
return FIELD.equals(accessor) || ALL.equals(accessor);
}
}
1.2,JavaBeanDescriptor类。
该类主要定义了表示不同类型的常量
public final class JavaBeanDescriptor implements Serializable, Iterable<Map.Entry<Object, Object>> {
private static final long serialVersionUID = -8505586483570518029L;
public static final int TYPE_CLASS = 1;
public static final int TYPE_ENUM = 2;
public static final int TYPE_COLLECTION = 3;
public static final int TYPE_MAP = 4;
public static final int TYPE_ARRAY = 5;
/** @see com.alibaba.dubbo.common.utils.ReflectUtils#isPrimitive(Class) */
public static final int TYPE_PRIMITIVE = 6;
public static final int TYPE_BEAN = 7;
private static final String ENUM_PROPERTY_NAME = "name";
private static final String CLASS_PROPERTY_NAME = "name";
private static final String PRIMITIVE_PROPERTY_VALUE = "value";
//以下方法省略
}
1.3,JavaBeanSerializeUtil
该类对对象进行序列化成JavaBeanDescriptor。以及可以将JavaBeanDescriptor反序列化为对象。注意里面使用的cache类型为IdentityHashMap。
2,bytecode包
2.1 Proxy类
生成代理对象的工具类,主要是基于javassist的实现
public abstract class Proxy
{
//利用AtomicLong自增获取一个long数组做为生存类的后缀,防止冲突
private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ return null; }
};
public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args){ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented."); }
};
//缓存的map对象
private static final Map> ProxyCacheMap = new WeakHashMap>();
private static final Object PendingGenerationMarker = new Object();
/**
* Get proxy.
*
* @param ics interface class array.
* @return Proxy instance.
*/
public static Proxy getProxy(Class>... ics)
{
return getProxy(ClassHelper.getCallerClassLoader(Proxy.class), ics);
}
/**
* Get proxy.
* @param cl class loader.
* @param ics interface class array.
*
* @return Proxy instance.
*/
public static Proxy getProxy(ClassLoader cl, Class>... ics)
{
if( ics.length > 65535 )
throw new IllegalArgumentException("interface limit exceeded");
StringBuilder sb = new StringBuilder();
//遍历所有入参的接口,以;进行分割
for(int i=0;iif( !ics[i].isInterface() )
throw new RuntimeException(itf + " is not a interface.");
Class> tmp = null;
try
{
tmp = Class.forName(itf, false, cl);
}
catch(ClassNotFoundException e)
{}
if( tmp != ics[i] )
throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
sb.append(itf).append(';');
}
// use interface class name list as key.
String key = sb.toString();
//通过classloader去缓存map中拿出对应的map。
Map cache;
synchronized( ProxyCacheMap )
{
cache = ProxyCacheMap.get(cl);
if( cache == null )
{
cache = new HashMap();
ProxyCacheMap.put(cl, cache);
}
}
Proxy proxy = null;
//如果查询获得对象,则返回,否则把key和PendingGenerationMarker插入
synchronized( cache )
{
do
{
Object value = cache.get(key);
if( value instanceof Reference> )
{
proxy = (Proxy)((Reference>)value).get();
if( proxy != null )
return proxy;
}
if( value == PendingGenerationMarker )
{
try{ cache.wait(); }catch(InterruptedException e){}
}
else
{
cache.put(key, PendingGenerationMarker);
break;
}
}
while( true );
}
long id = PROXY_CLASS_COUNTER.getAndIncrement();
String pkg = null;
ClassGenerator ccp = null, ccm = null;
try
{
ccp = ClassGenerator.newInstance(cl);
//用来存放接口所定义的所有方法,可以进行去重
Set worked = new HashSet();
List methods = new ArrayList();
for(int i=0;iif( !Modifier.isPublic(ics[i].getModifiers()) )
{
String npkg = ics[i].getPackage().getName();
if( pkg == null )
{
pkg = npkg;
}
else
{
if( !pkg.equals(npkg) )
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
ccp.addInterface(ics[i]);
for( Method method : ics[i].getMethods() )
{
String desc = ReflectUtils.getDesc(method);
if( worked.contains(desc) )
continue;
worked.add(desc);
int ix = methods.size();
Class> rt = method.getReturnType();
Class>[] pts = method.getParameterTypes();
StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
for(int j=0;j" args[").append(j).append("] = ($w)$").append(j+1).append(";");
code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
if( !Void.TYPE.equals(rt) )
code.append(" return ").append(asArgument(rt, "ret")).append(";");
methods.add(method);
ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
}
}
if( pkg == null )
pkg = PACKAGE_NAME;
// create ProxyInstance class.
/**
* 创建代理实例对象ProxyInstance
* 类名为 pkg + “.poxy”+id = 包名 + “.poxy” +自增数值
* 添加静态字段Method[] methods;
* 添加实例对象InvokerInvocationHandler hanler
* 添加构造器参数是InvokerInvocationHandler
* 添加无参构造器
* 利用工具类ClassGenerator生成对应的字节码
*
*/
String pcn = pkg + ".proxy" + id;
ccp.setClassName(pcn);
ccp.addField("public static java.lang.reflect.Method[] methods;");
ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
ccp.addConstructor(Modifier.PUBLIC, new Class>[]{ InvocationHandler.class }, new Class>[0], "handler=$1;");
ccp.addDefaultConstructor();
Class> clazz = ccp.toClass();
clazz.getField("methods").set(null, methods.toArray(new Method[0]));
// create Proxy class.
/**
* 创建代理对象,它的newInstance(handler)方法用来创建基于我们接口的代理
* 代理对象名Proxy + id,继承于Proxy, 所以要实现newInstance方法
* 添加默认构造器
* 实现方法newInstance代码, new pcn(hadler) 这里pcn就是前面生成的代理对象类名
* 利用工具类ClassGenerator生成字节码并实例化对象返回
*
*/
String fcn = Proxy.class.getName() + id;
ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn);
ccm.addDefaultConstructor();
ccm.setSuperClass(Proxy.class);
ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
Class> pc = ccm.toClass();
proxy = (Proxy)pc.newInstance();
}
catch(RuntimeException e)
{
throw e;
}
catch(Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
finally
{
// release ClassGenerator
if( ccp != null )
ccp.release();
if( ccm != null )
ccm.release();
synchronized( cache )
{
if( proxy == null )
cache.remove(key);
else
cache.put(key, new WeakReference(proxy));
cache.notifyAll();
}
}
return proxy;
}
2.2 Wrapper类
是生成“运行时class代码”的工具类,
主要的方法有
1,makeWrapper类,生成一个继承于Wrapper的类
2,
public static Wrapper getWrapper(Class> c){
while( ClassGenerator.isDynamicClass(c) ) // can not wrapper on dynamic class.
c = c.getSuperclass();
//Object类型的
if( c == Object.class )
return OBJECT_WRAPPER;
//先去Wrapper缓存中查找
Wrapper ret = WRAPPER_MAP.get(c);
if( ret == null ) {
//缓存中不存在,生成Wrapper类,放到缓存
ret = makeWrapper(c);
WRAPPER_MAP.put(c,ret);
}
return ret;
}
3,extension包
这是一个动态扩展包,dubbo包含了@SPI @Adaptive注解。dubbo如何利用配置和注解来做动态扩展呢?
3.1 ExtensionFactory类
根据class返回一个instance
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
T getExtension(Class type, String name);
}
接下来查看它的三个实现类
3.1.1 SpringExtensionFactory类
从ApplicationContext 获取这个bean
3.1.2 AdaptiveExtensionFactory类
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List factories;
public AdaptiveExtensionFactory() {
ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List list = new ArrayList();
for (String name : loader.getSupportedExtensions()) { // 将所有ExtensionFactory实现保存起来
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
public T getExtension(Class type, String name) {
// 依次遍历各个ExtensionFactory实现的getExtension方法,一旦获取到Extension即返回
// 如果遍历完所有的ExtensionFactory实现均无法找到Extension,则返回null
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
相当于一个代理入口,他会遍历当前系统中所有的ExtensionFactory实现来获取指定的扩展实现,获取到扩展实现或遍历完所有的ExtensionFactory实现。这里调用了ExtensionLoader的getSupportedExtensions方法来获取ExtensionFactory的所有实现,又回到了ExtensionLoader类。
3.1.3 SpiExtensionFactory类
用ExtensionLoader来动态扩展,获取instance
3.2 ExtensionLoader类(重点,将详细解读)
每一个ExtensionLoader实例仅负责加载特定SPI扩展的实现,因此想要获取某个扩展的实现,首先要获取到该扩展对应的ExtensionLoader实例,下面我们就来看一下获取ExtensionLoader实例的工厂方法getExtensionLoade
@SuppressWarnings("unchecked")
public static ExtensionLoader getExtensionLoader(Class type) {
if (type == null)
throw new IllegalArgumentException("Extension type == null");
if(!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
//只接受@SPI注解注释的接口类型
if(!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
//从缓存中获取对应的ExtensionLoader实例
ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
}
return loader;
}
接下来查看私有构造函数
private ExtensionLoader(Class> type) {
this.type = type;
// 如果扩展类型是ExtensionFactory,那么则设置为null
// 这里通过getAdaptiveExtension方法获取一个运行时自适应的扩展类型(每个Extension只能有一个@Adaptive类型的实现,如果没有dubbo会动态生成一个类)
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
从这个方法可以看到,我们调用getAdaptiveExtension来获取一个自适应的实现,接下来看看它的实现
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get(); // 首先判断是否已经有缓存的实例对象
if (instance == null) {
if(createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
instance = createAdaptiveExtension(); // 没有缓存的实例,创建新的AdaptiveExtension实例
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
}
else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
首先检查缓存的adaptiveInstance是否存在,如果存在则直接使用,否则的话调用createAdaptiveExtension方法来创建新的adaptiveInstance并且缓存起来。也就是说对于某个扩展点,每次调用ExtensionLoader.getAdaptiveExtension获取到的都是同一个实例。
private Class> getAdaptiveExtensionClass() {
getExtensionClasses(); // 加载当前Extension的所有实现,如果有@Adaptive类型,则会赋值为cachedAdaptiveClass属性缓存起来
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass(); // 没有找到@Adaptive类型实现,则动态创建一个AdaptiveExtensionClass
}
private Map> getExtensionClasses() {
Map> classes = cachedClasses.get(); // 判断是否已经加载了当前Extension的所有实现类
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses(); // 如果还没有加载Extension的实现,则进行扫描加载,完成后赋值给cachedClasses变量
cachedClasses.set(classes);
}
}
}
return classes;
}
在getExtensionClasses方法中,首先检查缓存的cachedClasses,如果没有再调用loadExtensionClasses方法来加载,加载完成之后就会进行缓存。也就是说对于每个扩展点,其实现的加载只会执行一次。我们看下loadExtensionClasses方法:
private Map> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if(defaultAnnotation != null) {
String value = defaultAnnotation.value(); // 解析当前Extension配置的默认实现名,赋值给cachedDefaultName属性
if(value != null && (value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
if(names.length > 1) { // 每个扩展实现只能配置一个名称
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if(names.length == 1) cachedDefaultName = names[0];
}
}
// 从配置文件中加载扩展实现类
Map> extensionClasses = new HashMap>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
从代码里面可以看到,在loadExtensionClasses中首先会检测扩展点在@SPI注解中配置的默认扩展实现的名称,并将其赋值给cachedDefaultName属性进行缓存,后面想要获取该扩展点的默认实现名称就可以直接通过访问cachedDefaultName字段来完成,比如getDefaultExtensionName方法就是这么实现的。从这里的代码中又可以看到,具体的扩展实现类型,是通过调用loadFile方法来加载,分别从一下三个地方加载:
META-INF/dubbo/internal/
META-INF/dubbo/
META-INF/services/
创建自适应扩展点实现类型和实例化就已经完成了,下面就来看下扩展点自动注入的实现injectExtension:
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {// 处理所有set方法
Class> pt = method.getParameterTypes()[0];// 获取set方法参数类型
try {
// 获取setter对应的property名称
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
Object object = objectFactory.getExtension(pt, property); // 根据类型,名称信息从ExtensionFactory获取
if (object != null) { // 如果不为空,说set方法的参数是扩展点类型,那么进行注入
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
这里可以看到,扩展点自动注入的一句就是根据setter方法对应的参数类型和property名称从ExtensionFactory中查询,如果有返回扩展点实例,那么就进行注入操作。到这里getAdaptiveExtension方法就分析完毕了。
接下来看看getExtension
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) { // 判断是否是获取默认实现
return getDefaultExtension();
}
Holder
private T createExtension(String name) {
Class> clazz = getExtensionClasses().get(name); // getExtensionClass内部使用cachedClasses缓存
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz); // 从已创建Extension实例缓存中获取
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance); // 属性注入
// Wrapper类型进行包装,层层包裹
Set> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
从代码中可以看到,内部调用了getExtensionClasses方法来获取当前扩展的所有实现,而getExtensionClassse方法会在第一次被调用的时候将结果缓存到cachedClasses变量中,后面的调用就直接从缓存变量中获取了。这里还可以看到一个缓存EXTENSION_INSTANCES,这个缓存是ExtensionLoader的静态成员,也就是全局缓存,存放着所有的扩展点实现类型与其对应的已经实例化的实例对象(是所有扩展点,不是某一个扩展点),也就是说所有的扩展点实现在dubbo中最多都只会有一个实例
接下来看看getActivateExtension
方法主要获取当前扩展的所有可自动激活的实现。可根据入参(values)调整指定实现的顺序,在这个方法里面也使用到getExtensionClasses方法中收集的缓存数据
public List getActivateExtension(URL url, String[] values, String group) {
List exts = new ArrayList();
List names = values == null ? new ArrayList(0) : Arrays.asList(values); // 解析配置要使用的名称
// 如果未配置"-default",则加载所有Activates扩展(names指定的扩展)
if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
getExtensionClasses(); // 加载当前Extension所有实现,会获取到当前Extension中所有@Active实现,赋值给cachedActivates变量
for (Map.Entry entry : cachedActivates.entrySet()) { // 遍历当前扩展所有的@Activate扩展
String name = entry.getKey();
Activate activate = entry.getValue();
if (isMatchGroup(group, activate.group())) { // 判断group是否满足,group为null则直接返回true
T ext = getExtension(name); // 获取扩展示例
// 排除names指定的扩展;并且如果names中没有指定移除该扩展(-name),且当前url匹配结果显示可激活才进行使用
if (! names.contains(name)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)
&& isActive(activate, url)) {
exts.add(ext);
}
}
}
Collections.sort(exts, ActivateComparator.COMPARATOR); // 默认排序
}
// 对names指定的扩展进行专门的处理
List usrs = new ArrayList();
for (int i = 0; i < names.size(); i ++) { // 遍历names指定的扩展名
String name = names.get(i);
if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { // 未设置移除该扩展
if (Constants.DEFAULT_KEY.equals(name)) { // default表示上面已经加载并且排序的exts,将排在default之前的Activate扩展放置到default组之前,例如:ext1,default,ext2
if (usrs.size() > 0) { // 如果此时user不为空,则user中存放的是配置在default之前的Activate扩展
exts.addAll(0, usrs); // 注意index是0,放在default前面
usrs.clear(); // 放到default之前,然后清空
}
} else {
T ext = getExtension(name);
usrs.add(ext);
}
}
}
if (usrs.size() > 0) { // 这里留下的都是配置在default之后的
exts.addAll(usrs); // 添加到default排序之后
}
return exts;
}
四,URL
URL 本来是用来远程寻址的,dubbo 用它来暴露服务
所有扩展点参数都包含URL参数,URL作为上下文信息贯穿整个扩展点设计体系。
URL采用标准格式:protocol://username:password@host:port/path?key=value&key=value
例如:injvm://127.0.0.1/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello
总结:
第一次看源码,还有很多不太理解的,但是随着越来越深入,会慢慢清晰,同时也借鉴了很多大牛的博客,如果有什么错误的地方,欢迎指出。