摘要:要构建自适应实例,先要有自适应的实现类,实现类有两种方式一种通过配置文件,一种是通过是字节码的方式动态生成。
SPI机制
SPI,即(service provider interface)机制,有很多组件的实现,如日志、数据库访问等都是采用这样的方式,一般通用组件为了提升可扩展性,基于接口编程,将操作接口形成标准规范,但是可以开放多种扩展实现,这种做法也符合开闭设计原则,使组件具有可插拨特性。不同的厂商或组织可以基于规范推出自己的实现,只需要在自己的jar包中通过配置文件和相应的实现类即可以实现扩展。甚至开发者自己也可以很方便对框架进行定制化实现。
JDK SPI介绍JDK实现spi服务查找: ServiceLoader。
举个例子:
首先定义下示例接口
package com.example; public interface Spi { booleanisSupport(String name); String sayHello(); }
ServiceLoader会遍历所有jar查找META-INF/services/com.example.Spi文件
A厂商提供实现
package com.a.example; public class SpiAImpl implements Spi { publicboolean isSupport(String name) { return"SPIA".equalsIgnoreCase(name.trim()); } public String syaHello() { return “hello 我是厂商A”; } }
在A厂商提供的jar包中的META-INF/services/com.example.Spi文件内容为:
com.a.example.SpiAImpl #厂商A的spi实现全路径类名
B厂商提供实现
package com.b.example; public class SpiBImpl implements Spi { publicboolean isSupport(String name) { return"SPIB".equalsIgnoreCase(name.trim()); } public String syaHello() { return “hello 我是厂商B”; } }
在B厂商提供的jar包中的META-INF/services/com.example.Spi文件内容为:
com.b.example.SpiBImpl #厂商B的spi实现全路径类名
ServiceLoader.load(Spi.class)读取厂商A、B提供jar包中的文件,ServiceLoader实现了Iterable接口可通过while for循环语句遍历出所有实现。
一个接口多种实现,就如策略模式一样提供了策略的实现,但是没有提供策略的选择, 使用方可以根据isSupport方法根据业务传入厂商名来选择具体的厂商。
public class SpiFactory { //读取配置获取所有实现 privatestatic ServiceLoader spiLoader = ServiceLoader.load(Spi.class); //根据名字选取对应实现 publicstatic Spi getSpi(String name) { for(Spi spi : spiLoader) { if(spi.isSupport(name) ) { returnspi; } } returnnull; } }Duddo SPI
Dubbo 改进了 JDK 标准的 SPI 的以下问题:
JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
如果扩展点加载失败,连扩展点的名称都拿不到了。
增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
示例在扩展类的jar包内,放置扩展点配置文件 META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
以扩展 Dubbo 的协议为例,在协议的实现 jar 包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:
xxx=com.alibaba.xxx.XxxProtocol
实现类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocol implemenets Protocol { // ... }ExtensionLoad
dubbo扩展机制的实现核心类是ExtensionLoad,几乎所有扩展实现都在这个类里面。每个可扩展接口的扩展实现类和实现实例的都管理通过是ExtensionLoad进行,每个接口维护一个单例的ExtensionLoad,所有可扩展接口的实现都维护在ExtensionLoad中,如下所示:
/** * SPI 类和ExtensionLoader映射 */ private static final ConcurrentMap, ExtensionLoader>> EXTENSION_LOADERS = new ConcurrentHashMap , ExtensionLoader>>();
在单例模式中,最典型的实现就是通过私有构造方法实现的:
private ExtensionLoader(Class> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
在dubbo扩展点实现过程中,有几个重要的特性需要提前了解一下:
扩展点自动包装自动包装扩展点的 Wrapper 类。ExtensionLoader 在加载扩展点时,如果加载到的扩展点有拷贝构造函数,则判定为扩展点 Wrapper 类。
Wrapper类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocolWrapper implemenets Protocol { Protocol impl; public XxxProtocol(Protocol protocol) { impl = protocol; } // 接口方法做一个操作后,再调用extension的方法 public void refer() { //... 一些操作 impl.refer(); // ... 一些操作 } // ... }
Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。这个是典型的装饰者模式,即真正的实现类是被包装在Wrapper之中,Wrapper类还做一些其它事情。
扩展点自动装配加载扩展点时,自动注入依赖的扩展点。加载扩展点时,扩展点实现类的成员如果为其它扩展点类型,ExtensionLoader 在会自动注入依赖的扩展点。ExtensionLoader 通过扫描扩展点实现类的所有 setter 方法来判定其成员。即 ExtensionLoader 会执行扩展点的拼装操作。这个类似于Spring的IOC,后面会专门介绍。
扩展点自适应在调用过程,自动选择一个扩展实现执行,一个扩展点只允许有一个自适应实现。dubbo通过@Adaptive注解标定自适应实现,这个注解可以在实现类上,也可以在方法上。比如ExtensionFactory的自适应实现就是通过在实现类AdaptiveExtensionFactory上加@Adaptive注解实现的:
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { ... }
如 Cluster就是通过在方法加@Adaptive实现的:
@SPI(FailoverCluster.NAME) public interface Cluster { /** * Merge the directory invokers to a virtual invoker. * * @param* @param directory * @return cluster invoker * @throws RpcException */ @Adaptive Invoker join(Directory directory) throws RpcException; }
这两种方式的自适应扩展类的实现方式也不同,在类上加注解是通过在实现上标识该类为自适应实现类,而在方法上加注解的,是通过动态代码生成自适应实现类。
扩展点自动激活对于集合类扩展点,比如:Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等,可以同时加载多个实现,此时,可以用自动激活来简化配置
在ExtensionLoader中比较重要的公用方法就是这些:
getExtensionLoader
getAdaptiveExtension
getActivateExtension
下面就详细剖析一下ExtensionLoader的实现流程。
获取ExtensionLoader流程每个可扩展接口对应的ExtensionLoader都是单例,唯一获取ExtensionLoader对象的入口就是ExtensionLoader::getExtensionLoader方法,如主要流程图:
首先通过ExtensionLoader::getExtensionLoader
public staticExtensionLoader getExtensionLoader(Class type) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if(!type.isInterface()) { throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); } if(!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } ExtensionLoader loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader (type)); loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); } return loader; }
会校验尝试获取Loader的接口是否有@SPI注解,先在缓存中找,如果没有缓存,则调用私有构造方法:
private ExtensionLoader(Class> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
这里有个重要的对象objectFactory,这个对象的作用就是自动装配依赖,也就是IOC,可以看出,除了ObjectFactory本身,所有扩展点都有ObjectFactory实例,这个也是通过SPI管理的,它是通过getAdaptiveExtension()方法获取,这就是后面要介绍自适应扩展实现,有关ObjectFactory的内容会在后面IOC中详细分析。
自适应扩展我们从getAdaptiveExtension()方法切入,这个方法要完成的任务就是获取该扩展点的自适应实现实例,其流程如下图所示:
主要完成以下工作:
1.检查自适应缓存是否存在。
2.如果缓存未命中,则开始自适应例构建过程。
3.要构建自适应实例,先要有自适应的实现类,实现类有两种方式:一种通过配置文件,一种是通过是字节码的方式动态生成。
配置文件配置的自适应类通过在实现类上面加@Adaptive注解,如
..... @Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { }
字节码生成的自适应实现类是在方法层面@Adaptive注解,如
@SPI("dubbo") public interface Protocol { ....省略代码 @AdaptiveExporter export(Invoker invoker) throws RpcException; @Adaptive Invoker refer(Class type, URL url) throws RpcException; void destroy(); }
4.优先加载配置文件,将自适应实现类缓存在cachedAdaptiveClass中,同时通过加载配置文件,也将激活实现缓存在cachedActivates之中,这个在后面的激活实现中有用到。将包装类实例缓存在cachedWrapperClasses。可以简单一窥加载配置文件的代码
private void loadFile(Map> extensionClasses, String dir) { String fileName = dir + type.getName(); try { Enumeration urls; ClassLoader classLoader = findClassLoader(); if (classLoader != null) { urls = classLoader.getResources(fileName); } else { urls = ClassLoader.getSystemResources(fileName); } if (urls != null) { while (urls.hasMoreElements()) { java.net.URL url = urls.nextElement(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8")); try { String line = null; while ((line = reader.readLine()) != null) { final int ci = line.indexOf("#"); if (ci >= 0) line = line.substring(0, ci); line = line.trim(); if (line.length() > 0) { try { String name = null; int i = line.indexOf("="); if (i > 0) { name = line.substring(0, i).trim(); line = line.substring(i + 1).trim(); } if (line.length() > 0) { Class> clazz = Class.forName(line, true, classLoader); //配置的实现必须实现该接口 if (! type.isAssignableFrom(clazz)) { throw new IllegalStateException("Error when load extension class(interface: " + type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + "is not subtype of interface."); } if (clazz.isAnnotationPresent(Adaptive.class)) { //如果是自适应实现 if(cachedAdaptiveClass == null) { cachedAdaptiveClass = clazz; } else if (! cachedAdaptiveClass.equals(clazz)) { //只允许有一个自适应实现类 throw new IllegalStateException("More than 1 adaptive class found: " + cachedAdaptiveClass.getClass().getName() + ", " + clazz.getClass().getName()); } } else { //如果不是自适应类 try { //判断是不是包装类,即是否有接口的构造方法 clazz.getConstructor(type); Set > wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet >(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } catch (NoSuchMethodException e) { //不是包装类 clazz.getConstructor(); if (name == null || name.length() == 0) { //找到Extension注解 name = findAnnotationName(clazz); if (name == null || name.length() == 0) { //如果Extension注解没有默认名称,则根据类的名称关系判断 if (clazz.getSimpleName().length() > type.getSimpleName().length() && clazz.getSimpleName().endsWith(type.getSimpleName())) { //如果实现类和接口有名称上关系,比如XXImpl则将后面的作为实现类标识 name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase(); } else { throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url); } } } String[] names = NAME_SEPARATOR.split(name); if (names != null && names.length > 0) { Activate activate = clazz.getAnnotation(Activate.class); if (activate != null) { cachedActivates.put(names[0], activate); } for (String n : names) { if (! cachedNames.containsKey(clazz)) { cachedNames.put(clazz, n); } Class> c = extensionClasses.get(n); if (c == null) { extensionClasses.put(n, clazz); } else if (c != clazz) { throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName()); } } } } } } } catch (Throwable t) { IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t); exceptions.put(line, e); } } } // end of while read lines } finally { reader.close(); } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", class file: " + url + ") in " + url, t); } } // end of while urls } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
5.加载完配置文件后,检查缓存的自适应实现类,若没有,则通过字节码技术生成自适应类。调用createAdaptiveExtensionClass()方法,实际上是通过拼接class文本,然后通过compiler编译文本生成class,这里又是一个自适应的类AdaptiveCompiler。
private Class> getAdaptiveExtensionClass() { //先通过配置文化加载实现类,并且识别自适应实现类 getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } //如果没有通过Adaptive注解标识的自适应实现类,则通过字节码创建 return cachedAdaptiveClass = createAdaptiveExtensionClass(); } ....省略代码 private Class> createAdaptiveExtensionClass() { String code = createAdaptiveExtensionClassCode(); ClassLoader classLoader = findClassLoader(); com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); }
@Adaptive public class AdaptiveCompiler implements Compiler { private static volatile String DEFAULT_COMPILER; public static void setDefaultCompiler(String compiler) { DEFAULT_COMPILER = compiler; } public Class> compile(String code, ClassLoader classLoader) { Compiler compiler; ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(Compiler.class); String name = DEFAULT_COMPILER; // copy reference if (name != null && name.length() > 0) { compiler = loader.getExtension(name); } else { compiler = loader.getDefaultExtension(); } return compiler.compile(code, classLoader); } }
下面是通过字节码动态生成的Protocol接口的自适应扩展Protocol$Adpative:
package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol { public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public int getDefaultPort() { throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker { if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl(); String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); } public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class { if (arg1 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg1; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.refer(arg0, arg1); } public void destroyServer() { throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroyServer() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } }自动激活扩展
在dubbo中,某些组件可以同时有多个实现同时加载时,就可以通过@Activate注解自动激活,常见的自动激活扩展,如过滤器Filter,有顺序要求,提供了三个排序属性,before、after和order。还有一些过滤条件,主要是通过分组和key,如Provider和consumer的过滤逻辑可能就不一样,Activate的源码如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate { /** * Group过滤条件。 */ String[] group() default {}; String[] value() default {}; /** * 排序信息,可以不提供。 */ String[] before() default {}; /** * 排序信息,可以不提供。 */ String[] after() default {}; /** * 排序信息,可以不提供。 */ int order() default 0; }
在ExtensionLoader中,有三个重载获取激活扩展实现的方法:
public List
public List
public List
后面两个也是通过调用第一个重载方法实现,下面来分析一下它的源码:
public ListgetActivateExtension(URL url, String[] values, String group) { List exts = new ArrayList (); List names = values == null ? new ArrayList (0) : Arrays.asList(values); if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); if (! names.contains(name) && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } Collections.sort(exts, ActivateComparator.COMPARATOR); } List usrs = new ArrayList (); for (int i = 0; i < names.size(); i ++) { 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)) { if (usrs.size() > 0) { exts.addAll(0, usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (usrs.size() > 0) { exts.addAll(usrs); } return exts; }
这个方法所做的工作无非就是在之前加载配置时缓存的cachedActivates中过滤查询符合条件的自动激动实例,并根据@Activate注解中配置的排序规则排序。
IOC注入在创建自适应实例时,都会调用ExtensionLoader的injectExtension方法:
private T createAdaptiveExtension() { try { //传入自适应实例注入到ExtensionLoader return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e); } } 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())) { Class> pt = method.getParameterTypes()[0]; try { String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); if (object != null) { 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; }
然后我们看到了ExtensionFactory对象,dubbo中的IOC实例是通过ExtensionFactory实现的,其实就是检测扩展实现类有没有通过set方法设置的属性,如果有,就通过ExtensionFactory加载而设置。
ExtensionFactory的类实现体系:
在构造ExtensionLoader对象时,有个对象extensionFactory是必须要创建的,可以看到它就是用自适应实例,而ExtensionFatocry的自适应实例便是AdaptiveExtensionFactory,通过下面它的源码,我们可以发现,它维护了其他非自适应扩展实例,其实也就两个SpiExtensionFactory和SpringExtensionFactory。尝试用这两个实例去加载,加载到便返回。
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final Listfactories; public AdaptiveExtensionFactory() { ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List list = new ArrayList (); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } public T getExtension(Class type, String name) { for (ExtensionFactory factory : factories) { T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
ExtensionFatocry 可以理解为对象工厂,只不过这里的对应就是Dubbo中的扩展Extension,AdaptiveExtensionFactory可以理解为通用扩展实现获取的入口,至于具体的获取方式分为两种,如果一种是通过Dubbo 自己的SPI方式加载到的扩展,同时还支持复用Srping 的方式,可以看看这两种实现的代码便可知:
public class SpiExtensionFactory implements ExtensionFactory { public总结T getExtension(Class type, String name) { if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type); if (loader.getSupportedExtensions().size() > 0) { return loader.getAdaptiveExtension(); } } return null; } } public class SpringExtensionFactory implements ExtensionFactory { private static final Set contexts = new ConcurrentHashSet (); public static void addApplicationContext(ApplicationContext context) { contexts.add(context); } public static void removeApplicationContext(ApplicationContext context) { contexts.remove(context); } @SuppressWarnings("unchecked") public T getExtension(Class type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } return null; } }
作为贯穿整个Dubbo设计始终的思想,SPI在整个框架中随处可见,本文围绕ExtensionLoader扩展点机制,通过一些dubbo组件扩展示例,分析了其核心源码和流程。希望可以对于理解Dubbo的扩展点乃至dubbo源码解析过程中有所帮助,最后总结几点:
对于每个扩展点,只维护一个ExtensionLoad,具体扩展实现类和实例,都是通过相应的ExtensionLoader获取的。
针对每个扩展实现的实例都是单例的,所以在扩展实现时应保证线程安全。
自适应实现只能有一个,自适应实现类获取有两种方式,一种是通过配置文件,这种就是针对@Adaptive注解在类级别的时,而@Adaptive注解在方法级别时,自适应实现类就需要通过字符码动态生成。
自动激活扩展实现可以有多个,一般情况下,采用自动激动方式扩展的一般都会有多个,正因为有多个,自动激动扩展实现可能有顺序性,且可以分组。
参考http://dubbo.apache.org/books...
https://blog.csdn.net/jdluoji...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69282.html
摘要:为了实现在模块装配的时候,不在模块里写死代码,就需要一种服务发现机制。就提供了这样一种机制为某个接口寻找服务实现,有点类似思想,将装配的控制权移到代码之外。即接口文件的全类名。五示例遵循上述第一条第点,这里为接口文件,其中和为两个实现类。 一、Dubbo内核 Dubbo内核主要包含SPI、AOP、IOC、Compiler。 二、JDK的SPI 1.spi的设计目标: 面向对象的设计里...
摘要:今天我想聊聊的另一个很棒的特性就是它的可扩展性。的扩展机制在的官网上,描述自己是一个高性能的框架。接下来的章节中我们会慢慢揭开扩展机制的神秘面纱。扩展扩展点的实现类。的定义在配置文件中可以看到文件中定义了个的扩展实现。 摘要: 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架。今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性。 Dubbo的扩展机制 在Dub...
摘要:在中配置,以配置为例整个,最先使用的地方从里面读取这个配置使用接口的中获取具体的实现类中有两个值当主线程被外部终止时,会触发,执行的与方法通知下面的锁操作,主线程正常走完代码,并最终停止。 spring是如何启动容器的 常见的一种在本地使用main方法启动spring的方法 public static void main(String[] args) throws Except...
摘要:属性上篇文章中,提到在获取扩展点接口对应的的时候,会执行私有构造函数。因为此时是,即当为时,即我们可以看出,所有非扩展点接口都会执行对应的实例的方法返回一个实例,即对象。 spring是如何获得容器中管理的类的 拿到applicationContext,就可以调用getBean方法来获得Spring的bean对象了 public class SpringContextUtil impl...
摘要:二注解该注解为了保证在内部调用具体实现的时候不是硬编码来指定引用哪个实现,也就是为了适配一个接口的多种实现,这样做符合模块接口设计的可插拔原则,也增加了整个框架的灵活性,该注解也实现了扩展点自动装配的特性。 Dubbo扩展机制SPI 前一篇文章《dubbo源码解析(一)Hello,Dubbo》是对dubbo整个项目大体的介绍,而从这篇文章开始,我将会从源码来解读dubbo再各个模块的实...
阅读 1516·2021-11-18 10:02
阅读 1657·2021-09-04 16:40
阅读 3169·2021-09-01 10:48
阅读 872·2019-08-30 15:55
阅读 1851·2019-08-30 15:55
阅读 1364·2019-08-30 13:05
阅读 3011·2019-08-30 12:52
阅读 1622·2019-08-30 11:24