dubbo源码深度解读一之common模块

2024-05-07 09:18

本文主要是介绍dubbo源码深度解读一之common模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

dubbo源码深度解读一之common模块

言:或许很多人会使用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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();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;i<ics.length;i++){String itf = ics[i].getName();if( !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<String, Object> cache;synchronized( ProxyCacheMap ){cache = ProxyCacheMap.get(cl);if( cache == null ){cache = new HashMap<String, Object>();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<String> worked = new HashSet<String>();List<Method> methods = new ArrayList<Method>();for(int i=0;i<ics.length;i++){if( !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<pts.length;j++)code.append(" 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 ClassGeneratorif( ccp != null )ccp.release();if( ccm != null )ccm.release();synchronized( cache ){if( proxy == null )cache.remove(key);elsecache.put(key, new WeakReference<Proxy>(proxy));cache.notifyAll();}}return proxy;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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> T getExtension(Class<T> type, String name);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来查看它的三个实现类 
3.1.1 SpringExtensionFactory类 
从ApplicationContext 获取这个bean

3.1.2 AdaptiveExtensionFactory类

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {private final List<ExtensionFactory> factories;public AdaptiveExtensionFactory() {ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();for (String name : loader.getSupportedExtensions()) { // 将所有ExtensionFactory实现保存起来list.add(loader.getExtension(name));}factories = Collections.unmodifiableList(list);}public <T> T getExtension(Class<T> type, String name) {// 依次遍历各个ExtensionFactory实现的getExtension方法,一旦获取到Extension即返回// 如果遍历完所有的ExtensionFactory实现均无法找到Extension,则返回nullfor (ExtensionFactory factory : factories) {T extension = factory.getExtension(type, name);if (extension != null) {return extension;}}return null;}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

相当于一个代理入口,他会遍历当前系统中所有的ExtensionFactory实现来获取指定的扩展实现,获取到扩展实现或遍历完所有的ExtensionFactory实现。这里调用了ExtensionLoader的getSupportedExtensions方法来获取ExtensionFactory的所有实现,又回到了ExtensionLoader类。

3.1.3 SpiExtensionFactory类 
用ExtensionLoader来动态扩展,获取instance

3.2 ExtensionLoader类(重点,将详细解读) 
每一个ExtensionLoader实例仅负责加载特定SPI扩展的实现,因此想要获取某个扩展的实现,首先要获取到该扩展对应的ExtensionLoader实例,下面我们就来看一下获取ExtensionLoader实例的工厂方法getExtensionLoade

@SuppressWarnings("unchecked")public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> 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<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);if (loader == null) {EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);}return loader;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

接下来查看私有构造函数

private ExtensionLoader(Class<?> type) {this.type = type;// 如果扩展类型是ExtensionFactory,那么则设置为null// 这里通过getAdaptiveExtension方法获取一个运行时自适应的扩展类型(每个Extension只能有一个@Adaptive类型的实现,如果没有dubbo会动态生成一个类)objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

从这个方法可以看到,我们调用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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

首先检查缓存的adaptiveInstance是否存在,如果存在则直接使用,否则的话调用createAdaptiveExtension方法来创建新的adaptiveInstance并且缓存起来。也就是说对于某个扩展点,每次调用ExtensionLoader.getAdaptiveExtension获取到的都是同一个实例。

private Class<?> getAdaptiveExtensionClass() {getExtensionClasses(); // 加载当前Extension的所有实现,如果有@Adaptive类型,则会赋值为cachedAdaptiveClass属性缓存起来if (cachedAdaptiveClass != null) {return cachedAdaptiveClass;}return cachedAdaptiveClass = createAdaptiveExtensionClass(); // 没有找到@Adaptive类型实现,则动态创建一个AdaptiveExtensionClass
}private Map<String, Class<?>> getExtensionClasses() {Map<String, Class<?>> classes = cachedClasses.get(); // 判断是否已经加载了当前Extension的所有实现类if (classes == null) {synchronized (cachedClasses) {classes = cachedClasses.get();if (classes == null) {classes = loadExtensionClasses(); // 如果还没有加载Extension的实现,则进行扫描加载,完成后赋值给cachedClasses变量cachedClasses.set(classes);}}}return classes;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在getExtensionClasses方法中,首先检查缓存的cachedClasses,如果没有再调用loadExtensionClasses方法来加载,加载完成之后就会进行缓存。也就是说对于每个扩展点,其实现的加载只会执行一次。我们看下loadExtensionClasses方法:

private Map<String, Class<?>> 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<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);loadFile(extensionClasses, DUBBO_DIRECTORY);loadFile(extensionClasses, SERVICES_DIRECTORY);return extensionClasses;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

从代码里面可以看到,在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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

这里可以看到,扩展点自动注入的一句就是根据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<Object> holder = cachedInstances.get(name);// 缓存if (holder == null) {cachedInstances.putIfAbsent(name, new Holder<Object>());holder = cachedInstances.get(name);}Object instance = holder.get();if (instance == null) {synchronized (holder) {instance = holder.get();if (instance == null) {instance = createExtension(name);// 没有缓存实例则创建holder.set(instance);// 缓存起来}}}return (T) instance;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
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<Class<?>> 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);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

从代码中可以看到,内部调用了getExtensionClasses方法来获取当前扩展的所有实现,而getExtensionClassse方法会在第一次被调用的时候将结果缓存到cachedClasses变量中,后面的调用就直接从缓存变量中获取了。这里还可以看到一个缓存EXTENSION_INSTANCES,这个缓存是ExtensionLoader的静态成员,也就是全局缓存,存放着所有的扩展点实现类型与其对应的已经实例化的实例对象(是所有扩展点,不是某一个扩展点),也就是说所有的扩展点实现在dubbo中最多都只会有一个实例

接下来看看getActivateExtension 
方法主要获取当前扩展的所有可自动激活的实现。可根据入参(values)调整指定实现的顺序,在这个方法里面也使用到getExtensionClasses方法中收集的缓存数据

public List<T> getActivateExtension(URL url, String[] values, String group) {List<T> exts = new ArrayList<T>();List<String> names = values == null ? new ArrayList<String>(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<String, Activate> entry : cachedActivates.entrySet()) { // 遍历当前扩展所有的@Activate扩展String name = entry.getKey();Activate activate = entry.getValue();if (isMatchGroup(group, activate.group())) { // 判断group是否满足,group为null则直接返回trueT 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<T> usrs = new ArrayList<T>();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,ext2if (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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

四,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

这篇关于dubbo源码深度解读一之common模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966937

相关文章

MySQL中时区参数time_zone解读

《MySQL中时区参数time_zone解读》MySQL时区参数time_zone用于控制系统函数和字段的DEFAULTCURRENT_TIMESTAMP属性,修改时区可能会影响timestamp类型... 目录前言1.时区参数影响2.如何设置3.字段类型选择总结前言mysql 时区参数 time_zon

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree

MySQL中的锁和MVCC机制解读

《MySQL中的锁和MVCC机制解读》MySQL事务、锁和MVCC机制是确保数据库操作原子性、一致性和隔离性的关键,事务必须遵循ACID原则,锁的类型包括表级锁、行级锁和意向锁,MVCC通过非锁定读和... 目录mysql的锁和MVCC机制事务的概念与ACID特性锁的类型及其工作机制锁的粒度与性能影响多版本

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit