当前位置: 首页 > news >正文

局域网及网站建设内容手机制作游戏软件

局域网及网站建设内容,手机制作游戏软件,凡科抽奖,阿里云虚拟主机网站吗文章目录前言普通SPI实现原理实例化扩展点源码分析扩展点加载流程分析LoadingStrategy分析接口定义接口实现加载原理loadClass方法分析自适应SPI实现原理自适应扩展代码生成分析自激活SPI简单使用原理分析Activate注解源码分析IOC实现原理objectFactory介绍总结AOP实现原理总结… 文章目录前言普通SPI实现原理实例化扩展点源码分析扩展点加载流程分析LoadingStrategy分析接口定义接口实现加载原理loadClass方法分析自适应SPI实现原理自适应扩展代码生成分析自激活SPI简单使用原理分析Activate注解源码分析IOC实现原理objectFactory介绍总结AOP实现原理总结本专栏对应Dubbo版本2.7.8。 官方文档地址https://dubbo.apache.org/zh/docsv2.7/dev/ 官方GitHub地址https://github.com/apache/dubbo/releases/tag/dubbo-2.7.8 前言 在上篇文章我们已经对Dubbo中的SPI有了简单的了解接下来我们通过源码详细了解其实现细节。 在本文中我将SPI分为普通SPI与之相对应的是自适应SPI这个概念是笔者“捏造”的为了更好的划分文章结构读者不必纠结字眼。 普通SPI实现原理 核心的API为 // 第一步获取到对应接口的ExtensionLoader ExtensionLoaderSpiService extensionLoader ExtensionLoader.getExtensionLoader(SpiService.class); // 第二步通过ExtensionLoader实例化具体扩展点 SpiService internal extensionLoader.getExtension(internal);获取ExtensionLoader的逻辑非常简单大家自行阅读源码即可如何创建扩展点才是我们的重点 实例化扩展点源码分析 在没有进行源码分析之前大家应该能想到要得到一个扩展点实现类对象起码要做这么几件事 根据接口名找到并解析配置文件加载对应的扩展点实现类类加载成功后就可以反射创建对象了之后再对这个对象完成IOC及AOP 实际上Dubbo也确实是这么做的,接下来我们分析其源码 扩展点实例化核心方法如下源码比较简单这里我只保留了其骨架我们先对整体流程有一个认知 // 直接定位到调用的核心方法 // name:为传入的扩展点名称 // wrap:代表是否要进行AOP默认为true private T createExtension(String name, boolean wrap) {// 1️⃣.加载扩展点实现类得到class对象Class? clazz getExtensionClasses().get(name);// 2️⃣.这里通过反射调用空参构造函数完成实例化T instance (T) EXTENSION_INSTANCES.get(clazz);if (instance null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());instance (T) EXTENSION_INSTANCES.get(clazz);}// 3️⃣.IOCinjectExtension(instance);// 4️⃣.AOPif (wrap) {// .....}// 5️⃣.扩展点生命周期进一步完成初始化initExtension(instance);return instance; }在上面的代码中我们可以清晰的看到整个扩展点实例化分为5步,如下图所示 扩展点加载流程分析 在这一小节中我们主要分析Dubbo是如何加载扩展点的核心代码位于org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses,如下 private MapString, Class? loadExtensionClasses() {// 我们可以在SPI的注解中指定默认要使用的SPI名称cacheDefaultExtensionName();MapString, Class? extensionClasses new HashMap();// dubbo中内置了一些加载策略for (LoadingStrategy strategy : strategies) {loadDirectory(extensionClasses, strategy.directory(), type.getName(),strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());// 这里主要是为了向下兼容alibaba DubboloadDirectory(extensionClasses, strategy.directory(), type.getName().replace(org.apache, com.alibaba), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());}return extensionClasses; }要理解上述代码我们首先要搞懂LoadingStrategy的作用其次我们知道在strategies这个集合中放入了哪些LoadingStrategy。 LoadingStrategy分析 接口定义 可以看到这个接口继承了PrioritizedPrioritized的主要作用是定义加载的优先级。LoadingStrategy的作用在于定义加载SPI配置文件时的策略例如从哪个目录下加载、哪些不需要加载等 public interface LoadingStrategy extends Prioritized {// 定义了SPI配置文件的加载地址String directory();// 目前没有看到哪个实现类复写了这个方法可忽略default boolean preferExtensionClassLoader() {return false;}// 排除指定包下的SPI实现类default String[] excludedPackages() {return null;}// 如果一个SPI存在多个同名的实现的时候是否要进行覆盖default boolean overridden() {return false;} }接口实现 在Dubbo中内置了三种LoadingStrategy分别为 DubboInternalLoadingStrategy加载优先级最高Integer.MIN_VALUE加载目录为META-INF/dubbo/internal/,不支持覆盖。这个策略主要是Dubbo内部使用的 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SKPgpOCS-1679484853206)(/Users/mingzhidai/Library/Application Support/typora-user-images/image-20211219161506784.png)] 注意这个策略的优先级是最高的因此META-INF/dubbo/internal/这个目录下的类会被最先加载同时它是不支持覆盖的因此如果同名的实现存在多个第一个会生效 DubboLoadingStrategy正常加载优先级0,加载目录为META-INF/dubbo/,支持覆盖。这个策略是提供给外部开发者使用的我们平常进行扩展时更多是使用这个目录。由于这个 注意这个策略的优先级低于DubboInternalLoadingStrategy因此META-INF/dubbo/这个目录下的类会晚于META-INF/dubbo/internal/中的类被加载同时它又能支持覆盖已存在的同名实现类这就意味在META-INF/dubbo/目录中的类的优先级是高于META-INF/dubbo/internal/的通过这种方式我们就能替换Dubbo中默认的SPI实现这也体现了内核插件的思想 ServicesLoadingStrategy加载目录为META-INF/services/加载优先级最低0同时也支持覆盖。这个策略兼容了JDK原生SPI的加载目录。 注意这个策略的优先级是最低的同时它支持覆盖因为这个目录下的类的优先级是最高的会覆盖之前加载的类。 整个优先级及是否覆盖的设计也体现了一个思想越靠近应用优先级越高方便扩展 加载原理 LoadingStrategy的加载本身使用的是JDK原生的SPI加载逻辑见org.apache.dubbo.common.extension.ExtensionLoader#loadLoadingStrategies,如下图所示: 我们查看Dubbo Jar包内的META-INF/services/目录也能看到以下内容 loadClass方法分析 在了解了LoadingStrategy之后我们回头继续分析扩展点实现类的加载流程 org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses ☞ 入口 ⇣⇣⇣⇣ org.apache.dubbo.common.extension.ExtensionLoader#loadDirectory ☞ 加载目录 ⇣⇣⇣⇣ org.apache.dubbo.common.extension.ExtensionLoader#loadResource ☞ 一个目录下会有很多配置文件逐个解析配置文件 ⇣⇣⇣⇣ org.apache.dubbo.common.extension.ExtensionLoader#loadClass ☞ 通过配置文件可以拿到全类名加载并缓存 整个流程还是非常清晰的先加载目录通过对前面LoadingStrategy学习大家应该知道不同加载策略的加载目录是不同的。目录加载完成后会得到一个配置文件列表之后通过loadResource方法逐个加载配置文件在这个过程中可以拿到所有扩展点实现的全类名最后加载所有的扩展点实现类并进行缓存。关于前面配置文件的加载较为简单本文不做详细介绍读者可自行阅读源码。我们着重看loadClass方法的处理逻辑代码如下 下面的代码忽略了一些简单及异常处理只保留了核心逻辑 // extensionClasses一个缓存mapkey为SPI名称value为对应的实现类Class对象 // resourceURL这个参数传入进来只是为了更好的描述异常信息 // clazz本次要被加载的类通过Class.forName(”全类名“, true, classLoader)加载而来 // overridden对应的加载策略是否允许覆盖已存在的类 private void loadClass(MapString, Class? extensionClasses, java.net.URL resourceURL, Class? clazz, String name,boolean overridden) throws NoSuchMethodException {// 1️⃣.根据是否存在Adaptive注解判断实现类是否是一个Adaptive类并进行缓存if (clazz.isAnnotationPresent(Adaptive.class)) {cacheAdaptiveClass(clazz, overridden);// 2️⃣.根据是否存在一个参数类型为当前SPI接口的构造函数判断是否是一个wrapper类用于AOP} else if (isWrapperClass(clazz)) {cacheWrapperClass(clazz);} else {// 3️⃣.SPI实现类必须要有一个空参构造函数// 这里相当于一个检查保证缓存的扩展点实现是可用的// 如果不存在这个构造函数这一步就会抛出异常clazz.getConstructor();// 4️⃣.如果使用在配置文件中没有对这个SPI扩展点命名// 那么尝试直接从实现类中解析出该扩展点的名称if (StringUtils.isEmpty(name)) {name findAnnotationName(clazz);}// 使用逗号对该name进行切割String[] names NAME_SEPARATOR.split(name);if (ArrayUtils.isNotEmpty(names)) {// 5️⃣.缓存自激活扩展实现类关于自激活我们在后文中分析cacheActivateClass(clazz, names[0]);for (String n : names) {// 缓存扩展点名称只会缓存第一个名称cacheName(clazz, n);// 6️⃣.缓存扩展点实现一个扩展点实现可以有多个名称// 但一个名称只能对应一个扩展点实现saveInExtensionClass(extensionClasses, clazz, n, overridden);}}} }上面代码逻辑非常简单配合注释大家基本能看懂注释中提到的自激活扩展实现类我会在后文进行分析。经过上面的分析我们可以得到下面一张关系图 一个SPI接口对应一个ExtensionLoader在ExtensionLoader中会按照不同的分类将加载的类缓存到不同字段中 到目前为止我们已经知道了扩展点实现类是如何加载的 对于整个扩展点实例化的流程我们已经完成了一大部分再回过头来看一下整个扩展点实例化的流程图如下 按照图中流程我现在应该跟大家介绍Dubbo中的IOC及AOP不过由于IOC依赖了自适应SPI所以这里我们先来详细了解一下自适应SPI关于其使用我已经在之前的文章中介绍过了本文更多的是分析原理 自适应SPI实现原理 使用自适应扩展的API如下 ExtensionLoaderOrderService orderServiceExtensionLoader ExtensionLoader.getExtensionLoader(SPI接口).getAdaptiveExtension();自适应扩展的核心代码如下 private Class? getAdaptiveExtensionClass() {// 实际上就是在加载配置文件中的类并进行缓存 getExtensionClasses();// 是否存在被Adaptive注解修饰的自适应扩展类if (cachedAdaptiveClass ! null) {return cachedAdaptiveClass;}// 如果不存在的话通过代码生成创建一个自适应扩展类return cachedAdaptiveClass createAdaptiveExtensionClass(); }private Class? createAdaptiveExtensionClass() {// 生成代码其实就是字符串的拼接String code new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();ClassLoader classLoader findClassLoader();// 编译并返回具体的Class对象org.apache.dubbo.common.compiler.Compiler compiler ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();return compiler.compile(code, classLoader); }通过上面的代码要知道的是自适应SPI有两种形式 在扩展点实现类上添加Adaptive注解指定由这个类来实现自适应逻辑如果我们没有添加Adaptive注解 那么Dubbo会帮我们生成一个自适应类来完成适配逻辑 自适应扩展代码生成分析 关于代码生成的细节本文不做过多分析主要是一些字符串的拼接生成code字符串后再进行编译。我们重点关注最终生成的代码首先我们编写一个测试接口如下 SPI public interface AdaptiveSpi {/*** 注意这个方法有两个特征* p* 1.方法上有adaptive注解* p* 2.方法的参数中有一个URL需要注意的是这是一个org.apache.dubbo.common.URL,不是java.net.URL*/Adaptive(adaptive1)void adaptiveMethod1(URL url);Adaptive(adaptive2)void adaptiveMethod2(URLHolder url);Adaptivevoid adaptiveMethod3(URLHolder url, Invocation invocation);/*** 普通方法用于观察最终生成的代码*/void normalMethod();class URLHolder {private final URL url;public URLHolder(URL url) {this.url url;}public URL getUrl() {return url;}} }对应的生成的自适应扩展实现类代码如下 限于篇幅问题在下面的代码中我省去了一些检查相关代码。例如url不能为空扩展点名称不能为空等 public class AdaptiveSpi$Adaptive implements com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi {public void adaptiveMethod1(com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.URLHolder arg0) {org.apache.dubbo.common.URL url arg0.getUrl();String extName url.getParameter(adaptive1);com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi extension (com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi) ExtensionLoader.getExtensionLoader(com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.class).getExtension(extName);extension.adaptiveMethod2(arg0);}public void adaptiveMethod2(org.apache.dubbo.common.URL arg0) {org.apache.dubbo.common.URL url arg0;String extName url.getParameter(adaptive2);com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi extension (com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi) ExtensionLoader.getExtensionLoader(com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.class).getExtension(extName);extension.adaptiveMethod1(arg0);}public void adaptiveMethod3(com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.URLHolder arg0, org.apache.dubbo.rpc.Invocation arg1) {org.apache.dubbo.common.URL url arg0.getUrl();String methodName arg1.getMethodName();String extName url.getMethodParameter(methodName, adaptive.spi, null);com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi extension (com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi) ExtensionLoader.getExtensionLoader(com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.class).getExtension(extName);extension.adaptiveMethod3(arg0, arg1);}public void normalMethod() {throw new UnsupportedOperationException(The method public abstract void com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi.normalMethod() of interface com.easy4coding.dubbo.spi.service.adaptive.AdaptiveSpi is not adaptive method!);} }观察上面3个方法我们可以得出以下结论 自适应SPI接口上中的方法如果要用到自适应的能力必须要有Adaptive注解例如的normalMethod直接抛出了UnsupportedOperationException。所谓自适应能力我们在上篇文章中已经解释过了就是根据方法调用的参数去适配真实的SPI实现类 自适应SPI实际调用的是其它实际的扩展点实现类调用的API就是我们之前分析过的ExtensionLoader.getExtensionLoader(扩展点名称).getExtension()。 真正要使用的扩展点的名称是从URL的参数中解析出来的同时会将Adaptive注解中的值作为key,从而去从URL中解析出扩展点名称如果Adaptive注解中没有配置value属性的话那么会将类名转换为key如果类名是驼峰命名的方式的话那么会将驼峰转换为.分隔的形式例如AdaptiveSpi会被转换为adaptive.spi见adaptiveMethod3中的逻辑 另外根据自适应方法被Adaptive注解修饰的方法的参数中是否存在org.apache.dubbo.rpc.InvocationDubbo从URL中解析扩展点名称的方式也存在一些差异如果存在Invocation类型的参数那么调用的是url.getMethodParameter见adaptiveMethod3中的逻辑,如果不存在Invocation类型的参数调用的是url.getParameter org.apache.dubbo.rpc.Invocation代表一次具体的RPC调用,它持有调用过程中的变量比如方法名参数等 自激活SPI 接下来我们学习自激活SPI什么是自激活SPI呢顾名思义这一类的SPI扩展点是不需要显式的传入扩展点名称来获取的而是当满足一定条件时会自动返回。看到这里你可能还不明白没有关系我们来看一个例子。 简单使用 SPI public interface ActivateSpi {void activateMethod(); }public class FirstActivateSpiImpl implements ActivateSpi {Overridepublic void activateMethod() {System.out.println(activate first);} }// ❤️ 注意这个注解 Activate(second) public class SecondActivateSpiImpl implements ActivateSpi {Overridepublic void activateMethod() {System.out.println(activate second);} }public static void main(String[] args) { URL url new URL(,,0);url url.addParameter(second,1);// 明确表明要加载的扩展点是firstString[] extensionNames new String[]{first};final ListActivateSpi activateExtension ExtensionLoader.getExtensionLoader(ActivateSpi.class).getActivateExtension(url, extensionNames);activateExtension.forEach(ActivateSpi::activateMethod); }// 程序输出 // activate second // activate first不忘忘记要添加配置文件哈 firstcom.easy4coding.dubbo.spi.service.activate.FirstActivateSpiImpl secondcom.easy4coding.dubbo.spi.service.activate.SecondActivateSpiImpl在上面的例子中我们可以看到当我们调用getActivateExtension时显示传入的扩展点名称是first但此方法返回的扩展点不仅仅有firstsecond也被加载了这说明second这个扩展点自己激活了自己这就是自激活SPI接下来我们来分析一下其实现原理 原理分析 核心的API如下 // key用于从url中获取到具体的扩展点名称 public ListT getActivateExtension(URL url, String key, String group) {// 通过key从url中获取对应的value并将其作为扩展点名称String value url.getParameter(key);return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group); } // values代表要显式获取到的扩展点名称,具体源码我们在后文中分析 public ListT getActivateExtension(URL url, String[] values, String group) {...}我们基于以上API进行分析其原理 Activate注解 Documented Retention(RetentionPolicy.RUNTIME) Target({ElementType.TYPE, ElementType.METHOD}) public interface Activate {// 匹配通过API调用时方法参数中传入的groupString[] group() default {};// 用于跟Url中的参数进行匹配只有匹配成功扩展点才会激活String[] value() default {};// 从2.7版本已经过时用于排序指定顺序在某一扩展点前DeprecatedString[] before() default {};// 从2.7版本已经过时用于排序指定顺序在某一扩展点后DeprecatedString[] after() default {};// 用于排序int order() default 0; }Activate注解中的group及value属性主要用于跟之前提到的API中传入的参数进行匹配另外几个属性主要用于对加载的扩展点进行排序。 源码分析 核心代码位于org.apache.dubbo.common.extension.ExtensionLoader#getActivateExtension(URL,String[],String) 整个代码逻辑并不难核心逻辑可以分为两部分 判断传入的扩展点名称中是否包含-default如果包含代表不需要自激活的扩展点只加载名称在values数组中的扩展点实现。 -代表指定要排除某一个扩展点例如传入的valuse集合为[“name1”,“name2”,“-name3”]则代表要使用name1,name2及自激活的SPI扩展点实现同时排除名称为name3的扩展点实现 代码如下 if (!names.contains(REMOVE_VALUE_PREFIX DEFAULT_KEY)) {// 前文已经分析过调用这个方法会去读取SPI配置文件并加载所有的类缓存到不同的集合中getExtensionClasses();// cachedActivates中缓存的是被Activate注解修饰的扩展点实现for (Map.EntryString, Object entry : cachedActivates.entrySet()) {// name是扩展点名称String name entry.getKey();// value是Activate注解Object activate entry.getValue();String[] activateGroup, activateValue;// 获取注解中的值用于后续匹配if (activate instanceof Activate) {activateGroup ((Activate) activate).group();activateValue ((Activate) activate).value();// 兼容alibaba Dubbo} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {activateGroup ((com.alibaba.dubbo.common.extension.Activate) activate).group();activateValue ((com.alibaba.dubbo.common.extension.Activate) activate).value();} else {continue;}// 这里是重点哦if (isMatchGroup(group, activateGroup) !names.contains(name) !names.contains(REMOVE_VALUE_PREFIX name) isActive(activateValue, url)) {activateExtensions.add(getExtension(name));}}// 我们前文已经分析过Activate注解知道他有排序能力// 这里就是根据注解中的before、after及order进行排序activateExtensions.sort(ActivateComparator.COMPARATOR);}上面代码的核心在于如何判断一个SPI实现是不是自激活的对应判断条件如下 isMatchGroup(group, activateGroup)分组是否匹配。在group参数不为空的情况下要求Activate注解中的group的值必须跟方法参数group的值匹配。 !names.contains(name)不能是显示获取的扩展点主要是为了排序显示加载的扩展点会在后面进行统一加载 !names.contains(REMOVE_VALUE_PREFIX name)不能是显示排除的扩展点 isActive(activateValue, url)必须跟URL中的key是匹配的代码如下注释中已经做了详细介绍笔者不再过多介绍 加载指定名称的扩展点实现 ListT loadedExtensions new ArrayList();for (int i 0; i names.size(); i) {String name names.get(i);if (!name.startsWith(REMOVE_VALUE_PREFIX) !names.contains(REMOVE_VALUE_PREFIX name)) {if (DEFAULT_KEY.equals(name)) {if (!loadedExtensions.isEmpty()) {// default代表了自激活扩展点这里主要是为了排序activateExtensions.addAll(0, loadedExtensions);loadedExtensions.clear();}} else {loadedExtensions.add(getExtension(name));}}}if (!loadedExtensions.isEmpty()) {// 最终都放入activateExtensions集合中统一返回activateExtensions.addAll(loadedExtensions);}不知道大家有没有注意到在分析上面两步时文中都提到了一个词排序。主要是因为这个方法最终返回的扩展点集合包含了两部分内容 自激活的扩展点指定名称显示申明要使用的扩展点通过values参数申明 对于自激活的扩展点由于它们都被Activate注解修饰因此可以直接依赖Activate注解对其进行排序但是另外一部分显示要申明的扩展点要怎么办呢Dubbo的做法是 默认自激活扩展点的顺序高于显式申明要使用的扩展点所以最后一行代码调用了activateExtensions.addAll(loadedExtensions)可以在values参数中通过传入default值的方式来指定自激活扩展点的顺序。举个例子如果传入的values值为[“name1”,“name2”,“default”,“name3”]那么name1,“name2对应的扩展点实现的顺序高于自激活扩展点的顺序自激活扩展点的顺序高于name3对应的扩展点实现。如果传入的如果传入的values值为[“name1”,“name2”,“name3”]不包含default的情况下自激活扩展点的顺序高于name1”,“name2”,name3对应的扩展点实现 到现在为止我们已经基本已经掌握了Dubbo中的SPI的核心内容接下来我们要学习更高阶的知识了☞Dubbo中的IOC及AOP 通过前文我们应该知道IOC及AOP发生在扩展点实例化的过程中整个流程图如下 核心代码如下 private T createExtension(String name, boolean wrap) {// 1️⃣.加载扩展点实现类得到class对象Class? clazz getExtensionClasses().get(name);// 2️⃣.这里通过反射调用空参构造函数完成实例化T instance (T) EXTENSION_INSTANCES.get(clazz);if (instance null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());instance (T) EXTENSION_INSTANCES.get(clazz);}// 3️⃣.IOCinjectExtension(instance);// 4️⃣.AOPif (wrap) {// .....}// 5️⃣.扩展点生命周期进一步完成初始化initExtension(instance);return instance; }接下来我们来分析整个IOC的过程代码并不难哈 IOC实现原理 核心代码如下 可以看到代码真的非常简单大概逻辑分为这么几步 判断setter方法上是否有DisableInject注解这个注解代表不需要进行注入从objectFactory中获取到一个指定名称的对象并反射调用setter方法进行注入 所以我们要理解IOC首先要搞懂objectFactory是什么 objectFactory介绍 我们可以看到objectFactory是在创建ExtensionLoader的过程中被初始化的同时它是一个自适应SPI对应的接口类型为ExtensionFactory。这种情况我们首先去查找它的SPI配置文件如下 在其配置文件中存在三个SPI实现类 springorg.apache.dubbo.config.spring.extension.SpringExtensionFactory adaptiveorg.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory spiorg.apache.dubbo.common.extension.factory.SpiExtensionFactory我们分别查看对应的三个SPI实现会发在在AdaptiveExtensionFactory这个实现类有一个Adaptive注解代表调用API获取自适应SPI时真正返回的是这个类这个类做的更多的是适配的工作真正干活的还是SpringExtensionFactory及SpiExtensionFactory。SpringExtensionFactory这个类的作用是从Spring容器中获取到指定的Bean而SpiExtensionFactory这个类的作用是依赖Dubbo的SPI机制获取到指定的对象它们都是服务于Dubbo的IOC机制。 因为代码比较简单这里我们就看一下AdaptiveExtensionFactory的代码 AdaptiveExtensionFactory 注意哦dubbo中SPI实现类的优先级会高于spring容器中bean的优先级 现在我们已经知道了objectFactory的作用那么IOC就已经没有任何秘密。简单总结一下 总结 IOC发生的时机在实例化SPI实现时进行IOCIOC的条件 存在setter方法setter方法上没有DisableInject注解在进行IOC时被注入的对象是通过objectFactory获取objectFactory是通过自适应SPI进行初始化的实际上它会优先尝试使用Dubbo的SPI获取一个对象如果获取到了只会返回。如果没有获取到那么会再次从Spring容器中获取一个对应的bean。 AOP实现原理 AOP的实现就更加简单了实现AOP的关键是依赖通过loadExtensionClasses方法加载的wrapper类还记得loadExtensionClasses干了啥吗回顾一下这张图 AOP的核心代码如下 Dubbo的AOP说白了就是依靠wrapper类来对真实的扩展点进行一次包装wrapper类持有一个真实的扩展点实现引用 总结 这篇文章我们分析了Dubbo中的各种SPI实现以及Dubbo基于SPI扩展出来功能IOC、AOP。我相信只要大家认真看完这篇文章积极动手实践搞懂Dubbo的SPI是没有任何问题。要学好Dubbo掌握SPI是第一步整个框架中用到SPI的地方数不胜数。 谢谢你看完这篇文章也请你谢谢认真学习的自己
文章转载自:
http://www.morning.bdzps.cn.gov.cn.bdzps.cn
http://www.morning.wjhqd.cn.gov.cn.wjhqd.cn
http://www.morning.1000sh.com.gov.cn.1000sh.com
http://www.morning.fxzlg.cn.gov.cn.fxzlg.cn
http://www.morning.rkypb.cn.gov.cn.rkypb.cn
http://www.morning.rgxcd.cn.gov.cn.rgxcd.cn
http://www.morning.fyglg.cn.gov.cn.fyglg.cn
http://www.morning.nqrdx.cn.gov.cn.nqrdx.cn
http://www.morning.rmpkn.cn.gov.cn.rmpkn.cn
http://www.morning.tqsgt.cn.gov.cn.tqsgt.cn
http://www.morning.wqkzf.cn.gov.cn.wqkzf.cn
http://www.morning.gnkbf.cn.gov.cn.gnkbf.cn
http://www.morning.cylbs.cn.gov.cn.cylbs.cn
http://www.morning.smrty.cn.gov.cn.smrty.cn
http://www.morning.mqgqf.cn.gov.cn.mqgqf.cn
http://www.morning.cylbs.cn.gov.cn.cylbs.cn
http://www.morning.gychx.cn.gov.cn.gychx.cn
http://www.morning.ns3nt8.cn.gov.cn.ns3nt8.cn
http://www.morning.jkcnq.cn.gov.cn.jkcnq.cn
http://www.morning.qsy38.cn.gov.cn.qsy38.cn
http://www.morning.wjlnz.cn.gov.cn.wjlnz.cn
http://www.morning.mfcbk.cn.gov.cn.mfcbk.cn
http://www.morning.qymqh.cn.gov.cn.qymqh.cn
http://www.morning.hpmzs.cn.gov.cn.hpmzs.cn
http://www.morning.zkrzb.cn.gov.cn.zkrzb.cn
http://www.morning.pxdgy.cn.gov.cn.pxdgy.cn
http://www.morning.zsyrk.cn.gov.cn.zsyrk.cn
http://www.morning.xjkfb.cn.gov.cn.xjkfb.cn
http://www.morning.zxdhp.cn.gov.cn.zxdhp.cn
http://www.morning.twwts.com.gov.cn.twwts.com
http://www.morning.yhgbd.cn.gov.cn.yhgbd.cn
http://www.morning.ptxwg.cn.gov.cn.ptxwg.cn
http://www.morning.ykgp.cn.gov.cn.ykgp.cn
http://www.morning.lwlnw.cn.gov.cn.lwlnw.cn
http://www.morning.mftdq.cn.gov.cn.mftdq.cn
http://www.morning.nyjgm.cn.gov.cn.nyjgm.cn
http://www.morning.qlckc.cn.gov.cn.qlckc.cn
http://www.morning.wncb.cn.gov.cn.wncb.cn
http://www.morning.pnmgr.cn.gov.cn.pnmgr.cn
http://www.morning.mxcgf.cn.gov.cn.mxcgf.cn
http://www.morning.pbbzn.cn.gov.cn.pbbzn.cn
http://www.morning.lmqfq.cn.gov.cn.lmqfq.cn
http://www.morning.hrtwt.cn.gov.cn.hrtwt.cn
http://www.morning.jytrb.cn.gov.cn.jytrb.cn
http://www.morning.msbpb.cn.gov.cn.msbpb.cn
http://www.morning.lwsct.cn.gov.cn.lwsct.cn
http://www.morning.jgrjj.cn.gov.cn.jgrjj.cn
http://www.morning.tgxrm.cn.gov.cn.tgxrm.cn
http://www.morning.pangucheng.cn.gov.cn.pangucheng.cn
http://www.morning.mrckk.cn.gov.cn.mrckk.cn
http://www.morning.tntqr.cn.gov.cn.tntqr.cn
http://www.morning.qrhh.cn.gov.cn.qrhh.cn
http://www.morning.tnqk.cn.gov.cn.tnqk.cn
http://www.morning.rzjfn.cn.gov.cn.rzjfn.cn
http://www.morning.rkwlg.cn.gov.cn.rkwlg.cn
http://www.morning.poapal.com.gov.cn.poapal.com
http://www.morning.gcqdp.cn.gov.cn.gcqdp.cn
http://www.morning.skfkx.cn.gov.cn.skfkx.cn
http://www.morning.lkkgq.cn.gov.cn.lkkgq.cn
http://www.morning.znlhc.cn.gov.cn.znlhc.cn
http://www.morning.pmdlk.cn.gov.cn.pmdlk.cn
http://www.morning.wzwpz.cn.gov.cn.wzwpz.cn
http://www.morning.mcpdn.cn.gov.cn.mcpdn.cn
http://www.morning.djxnw.cn.gov.cn.djxnw.cn
http://www.morning.pwxkn.cn.gov.cn.pwxkn.cn
http://www.morning.pwhjr.cn.gov.cn.pwhjr.cn
http://www.morning.jhqcr.cn.gov.cn.jhqcr.cn
http://www.morning.litao4.cn.gov.cn.litao4.cn
http://www.morning.twdkt.cn.gov.cn.twdkt.cn
http://www.morning.pnljy.cn.gov.cn.pnljy.cn
http://www.morning.qnxkm.cn.gov.cn.qnxkm.cn
http://www.morning.phechi.com.gov.cn.phechi.com
http://www.morning.cprbp.cn.gov.cn.cprbp.cn
http://www.morning.xrpwk.cn.gov.cn.xrpwk.cn
http://www.morning.huayaosteel.cn.gov.cn.huayaosteel.cn
http://www.morning.njntp.cn.gov.cn.njntp.cn
http://www.morning.gjxr.cn.gov.cn.gjxr.cn
http://www.morning.fhkr.cn.gov.cn.fhkr.cn
http://www.morning.dmtwz.cn.gov.cn.dmtwz.cn
http://www.morning.tbstj.cn.gov.cn.tbstj.cn
http://www.tj-hxxt.cn/news/263068.html

相关文章:

  • 必须在当地网站备案机械公司网站模板
  • 自己做网站要会什么软件下载技术支持 贵阳贵阳网站建设
  • 门户网站推广优势贵阳市城乡建设局网站
  • 昆明房产网站建设渠道招商
  • 镇江网站制作网站城市切换如何做
  • 一个网站备案两个域名吗wordpress 3.9.1 漏洞
  • 前期的网站建设的难度王业美
  • 做网站去哪找wordpress语言的设置
  • 临沂网站制作公司六安城市网招聘
  • 淮北论坛招聘最新消息wordpress+极致优化
  • 申请网站域名多少钱wordpress mdtf
  • 在linux系统上用什么做网站阿里云服务器在哪里
  • 网站建立数据库wordpress后台怎么登陆
  • 建设旅游网站需要多少钱数码产品商务网站建设
  • 茂名专业网站建设公司找人做网站需要交接什么
  • 大学生做外包项目的网站宁波网络营销推广
  • 绵阳 网站建设整站seo
  • 网站建设一条龙怎么样内蒙古做网站的公司有哪些
  • 在哪几个网站里可以做淘客360怎么做网站搜索
  • 可以做动画的网站都有哪些推广公司游戏
  • 福建住房与城乡建设厅网站wordpress 音乐页面
  • 免费公司网站建站wordpress娱乐插件
  • 中国建设银行网站公积金查询wordpress自动清缓存
  • 网站建设的研发项目网站推广策划的思路
  • 建设进出口外贸网站一级a做爰片了网站
  • pc网站优化排名营销做得好的品牌
  • 网站维护的内容和步骤江苏手机网站建设
  • 网站关键词优化排名要怎么做网站建设 申请报告
  • 我做网站了重庆推广一个网站
  • 新手建站教程报价单企业网站seo模板