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

有谁帮做网站的哈尔滨龙彩做网站多少钱

有谁帮做网站的,哈尔滨龙彩做网站多少钱,wordpress图文教程,贵阳小程序开发软件公司文章目录一、什么是SPI机制二、Java原生的SPI机制2.1、javaSPI示例2.1.1、编写接口和实现类2.1.2、编写配置文件2.1.3、通过SPI机制加载实现类2.1.4、JAVA SPI 源码解析2.1.4.1、ServiceLoader#load2.1.4.2、ServiceLoader构造方法2.1.4.3、ServiceLoader#reload2.1.4.4、LazyI… 文章目录一、什么是SPI机制二、Java原生的SPI机制2.1、javaSPI示例2.1.1、编写接口和实现类2.1.2、编写配置文件2.1.3、通过SPI机制加载实现类2.1.4、JAVA SPI 源码解析2.1.4.1、ServiceLoader#load2.1.4.2、ServiceLoader构造方法2.1.4.3、ServiceLoader#reload2.1.4.4、LazyIterator2.1.4.5、LazyIterator#hasNext2.1.4.6、LazyIterator#hasNextService2.1.4.7、LazyIterator#parse2.1.4.7、LazyIterator#parse2.1.4.7、LazyIterator#next2.1.5、JAVA SPI 优缺点二、Dubbo的SPI机制2.1、Dubbo SPI 示例2.1.1、编写接口和实现类2.1.2、编写配置文件2.1.3、通过Dubbo SPI 加载实现类2.2、扩展点注解2.2.1、SPI注解2.2.2、自适用Adaptive注解2.2.2.1、Adaptive使用场景2.2.2.2、Adaptive使用示例2.2.3、自动激活Activate注解2.2.3.1、Activate使用场景2.2.3.2、Activate使用示例2.2.4、不自动注入DisableInject注解2.3、Dubbo SPI 机制源码解析2.3.1、ExtensionLoader#getExtensionLoader2.3.2、ExtensionLoader#getExtension2.3.3、ExtensionLoader#createExtension2.3.3.1、ExtensionLoader#getExtensionClasses2.3.3.1.1、ExtensionLoader#loadExtensionClasses2.3.3.1.2、ExtensionLoader#loadDirectory2.3.3.1.3、ExtensionLoader#loadResource2.3.3.1.4、ExtensionLoader#loadResource2.3.3.2、ExtensionLoader#injectExtension2.3.3.2.1、AdaptiveExtensionFactory#getExtension2.3.3.2.2、SpiExtensionFactory#getExtension2.3.3.2.3、SpiExtensionFactory#getExtension2.3.4、ExtensionLoader#getAdaptiveExtension2.3.4.1、ExtensionLoader#createAdaptiveExtension2.3.4.2、ExtensionLoader#getAdaptiveExtensionClass2.3.4.3、ExtensionLoader#createAdaptiveExtensionClass2.3.4.3、ExtensionLoader#createAdaptiveExtensionClassCode2.3.5、ExtensionLoader#getAdaptiveExtension一、什么是SPI机制 SPI 全称为 Service Provider Interface是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中并由服务加载器读取配置文件加载实现类。这样可以在运行时动态为接口替换实现类。正因此特性我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。 二、Java原生的SPI机制 Java SPI 规定在 classpath 下的 META-INF/services/ 目录里创建一个以服务接口命名的文件然后文件里面记录的是此 jar 包提供的具体实现类的全限定名。这样当我们引用了某个 jar 包的时候就可以去找这个 jar 包的 META-INF/services/ 目录再根据接口名找到文件然后读取文件里面的内容去进行实现类的加载与实例化。 2.1、javaSPI示例 2.1.1、编写接口和实现类 首先在我们当前的项目路径下定义一个接口和对应的两个实现类 2.1.2、编写配置文件 在classpath路径下的META-INF/services文件夹下配置好接口的实现类这里规则是文件名是接口的权限定名内容是实现类的权限定类名多个实现类之间用换行符分隔。 2.1.3、通过SPI机制加载实现类 这里我们首先通过ServiceLoader加载Person的实现类然后我们遍历调用实现类的say方法我们可以看到我们在配置文件中配置的两个实现类全部被加载出来了。 2.1.4、JAVA SPI 源码解析 2.1.4.1、ServiceLoader#load 获取当前线程的类加载器然后调用重载方法把刚刚获得类加载器也传进去在重载方法中会new一个ServiceLoader的实例。 2.1.4.2、ServiceLoader构造方法 对加载的class类型做判空判断有没有指定类加载器如果没有指定则使用系统类加载器初始化访问控制器调用reload方法重新加载 2.1.4.3、ServiceLoader#reload 这里首先会清空实例化好的缓存然后new出来了一个LazyIterator类型的迭代器这个是重点。 2.1.4.4、LazyIterator 在前面的我们的示例中我们会从serviceLoader中获取对应的iterator然后调用其hasNext和next方法我们看下这个iterator是不是上面的LazyIterator 这里我们看到这个迭代器首先会判断缓存中有没有如果缓存中有则直接取缓存中放好的实例如果没有则会调用lookupIterator的方法执行加载逻辑。这里为什么叫LazyIterator因为只有在调用到hasNext方法的时候才会去懒加载对应实现类的实例。 2.1.4.5、LazyIterator#hasNext 这里就是判断如果权限控制器不为空则通过doPrivileged方法让程序突破当前域权限的限制这个感兴趣可以了解最终都会调用hasNextService方法 2.1.4.6、LazyIterator#hasNextService 这里会使用classLoader加载META-INF/services/com.alibaba.dubbo.demo.spi.Person文件中的内容然后读取出来文件中的内容然后调用parse方法解析配置文件中的内容并赋值给pending迭代器。 2.1.4.7、LazyIterator#parse 这里就会遍历文件中的内容然后解析出来每一行就是对应的实现类的权限定类名然后收集起来返回。 2.1.4.7、LazyIterator#parse 1.这里就是会解析每一行然后过滤注释检查内容合法性还有根据缓存过滤避免重复加载。 2.1.4.7、LazyIterator#next 上面我们在hasNext方法中已经看到了他会去读取配置文件并缓存接口的实现类的权限定类名然后这些实现类什么时候进行实例化的我们看下next方法这里会直接调用nextService方法 获取下一个接口实现类的权限定类名然后通过反射创建出来实现类然后转成接口类型然后存入providers缓存中并返回 2.1.5、JAVA SPI 优缺点 优点 使用 Java SPI 机制的优势是实现解耦使第三方服务模块的装配控制的逻辑与调用者的业务代码分离而不是耦合在一起。应用程序可以根据实际业务情况启用框架扩展或替换框架组件。相比使用提供接口 jar 包供第三方服务使用的方式SPI 使得源框架不必关心接口的实现类的路径可以不使用硬编码 import 导入实现类。 缺点 虽然 ServiceLoader 使用了懒加载但结果还是通过遍历获取基本上可以说是全部实例化了一遍所以说这个懒加载机制在此场景下是浪费的。由于是遍历获取所以获取实现类的方式不够灵活。 多个并发多线程使用 ServiceLoader 类的实例是不安全的。 二、Dubbo的SPI机制 Dubbo 并未使用 Java 原生的 SPI 机制而是对其进行了增强使其能够更好的满足需求,Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中通过 ExtensionLoader我们可以加载指定的实现类。Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径。 2.1、Dubbo SPI 示例 2.1.1、编写接口和实现类 这里需要在接口上面加上SPI注解 2.1.2、编写配置文件 Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下与 Java SPI 实现类配置不同Dubbo SPI 是通过键值对的方式进行配置这样我们可以按需加载指定的实现类。 2.1.3、通过Dubbo SPI 加载实现类 这里我们可以通过ExtensionLoader来加载接口的不同实现可以实现按需加载 2.2、扩展点注解 在上面案例中我们需要在接口上面标注SPI注解Dubob给我们提供了一些扩展点注解可以帮我们动态选择对应的接口实现。 2.2.1、SPI注解 该注解可以使用在类接口枚举上在dubbo框架中都使用在接口上它的作用就是标记该接口是一个dubbo spi接口是一个扩展点可以有多个接口的实现。该注解有一个value属性表示该接口的默认实现。 2.2.2、自适用Adaptive注解 该注解可以使用在类接口枚举方法上面。如果标注在接口的方法上时可以根据参数动态获取实现类在第一次getExtension时会自动生成和编译一个动态的Adaptive类达到动态实现类的效果。如果标注在实现类上的时候主要是为了直接固定对应的实现而不需要动态生成代码实现。 该注解有一个参数value是个string数组类型表示可以通过多个元素依次查找实现类。 2.2.2.1、Adaptive使用场景 举例一个接口有三个方法分别是methodAmethodBmethodC。此接口有三个实现类impl1impl2impl3。接口通过SPI注解指定默认实现为impl1通过Adaptive注解及URL参数生成一个动态类可以完成以下动作。 接口能将每个方法的实现都对应不同实现类。例如接口可以的methodA由impl1执行methodB由impl2执行methodC由impl3执行。 接口能让方法按一定优先级选择实现类来执行。例如methodA方法上有注解Adaptive({“key1”,“key2”,“key3”})先尝试查找参数URL中key1对应的实现类未指定则取key2还未指定则key3再没指定则使用SPI注解规定的默认实现类去执行方法。 2.2.2.2、Adaptive使用示例 这里在接口上通过SPI指定了默认实现为wheelMaker1并且通过在方法上标注Adaptive注解可以动态从url中解析出来key对应的值并找到起对应的实现类。 这里在配置文件中指定WheelMaker的三个实现。 这里我们构造了一个url并指定了一些key然后调用ExtensionLoader#getAdaptiveExtension方法获得自适应扩展实现通过测试案例我们可以发现方法调用的都是不同的实现 这里makeWheelA方法上面标注了Adaptive注解这里value属性为空则会从url中查找wheel.maker对应的value这里wheel.maker是接口WheelMark的转换将驼峰处分开并转换成小写以.连接起来然后就找到实现类wheelMaker2了这里makeWheelB方法上标注了 Adaptive(“key4”)这里指定了key4但是我们的url中没有传key4这里会匹配不到然后他就会走到我们的在SPI注解中指定的默认实现wheelMaker1这里makeWheelC方法上标注了 Adaptive({“key3”,“key2”,“key1”})这里指定了3个会从url中按顺序查找这里先查找key3然后就找到了wheelMaker3如果没找到key3再往下找key2。 2.2.3、自动激活Activate注解 该注解可以标记在类接口枚举和方法上主要使用在有多个扩展点实现需要根据不通条件激活的场景中 Activate参数解释 group表示URL中的分组如果匹配的话就激活可以设置多个value 查找URL中如果含有该key值就会激活before填写扩展点列表表示哪些扩展点需要在本扩展点的前面after表示哪些扩展点需要在本扩展点的后面order 排序信息 2.2.3.1、Activate使用场景 在Dubbo中有Filter使用对于Filter来说我们会遇到这样的问题Filter自身有很多的实现我们希望某种条件下使用A实现另外情况下使用B实现这个时候我们前面介绍SPI和Adaptive就不能满足我们要求了这个时候我们就需要使用Activate。 Activate注解表示一个扩展是否被激活(使用),可以放在类定义和方法上Dubbo中用它在扩展类定义上表示这个扩展实现激活条件和时机。 2.2.3.2、Activate使用示例 这里下面这个接口会有多个实现分别有默认实现多个组排序从URL获取值的实现。 在resources下的META-INF/dubbo下面新建接口的权限定文件名 这里可以通过测试案例看到我们可以我们指定的3个注解属性的作用: group 修饰的实现类可以列举为一种标签标签用来区分是在 Provider 端被激活还是在 Consumer 端被激活value 修饰的实现类只在 URL 参数中出现指定的 key 时才会被激活order 用来确定扩展实现类的排序 2.2.4、不自动注入DisableInject注解 该注解可以使用在类接口方法上在createExtension的时候表示不自动注入在ExtensionLoader 类中创建子类实现的时候会自动注入由ExtensionLoader管理的类就会调用 injectExtension(instance)方法然后在方法遍历的时候会检测有没有该DisableInject注解如果有的话就会跳过不会自动注入。这里比较简单就不搞使用案例了后面分析源码我们可以看到其实现。 2.3、Dubbo SPI 机制源码解析 2.3.1、ExtensionLoader#getExtensionLoader 首先坐下校验判断类型是否为空判断是否是个接口类判断接口上面是否标注了SPI注解从缓存中找之前有没有创建过同样类型的ExtensionLoader有就从缓存中获取没有则new一个出来返回。 2.3.2、ExtensionLoader#getExtension 方法是获取某个类型具体的实现类这里首先从缓存中获取如果缓存中没有则会new一个holderput到缓存中这里会对holder对象进行加锁防止相同实例重复创建调用createExtension创建对应的实现类并设置到holder对象中 2.3.3、ExtensionLoader#createExtension 这里首先调用getExtensionClasses方法获取接口对应的所有的扩展实现类然后根据名称获取对应的扩展实现类。然后判断扩展实例缓存中有没有这个实现类的对象如果有说明之前已经创建过这个类的实例了如果没有则会通过反射创建这个类的实例调用injectExtension方法向创建出来的对象注入依赖的属性对依赖注入后的实例进行AOP(Wrapper),把当前接口类的所有的Wrapper全部⼀层⼀层包裹在实例对象上每包裹个Wrapper后也会对Wrapper对象进行依赖注入。返回最终的Wrapper对象。 2.3.3.1、ExtensionLoader#getExtensionClasses 这里首先从缓存中获取当前接口的所有扩展点实现类如果没有那么需要解析配置文件进行加载 2.3.3.1.1、ExtensionLoader#loadExtensionClasses 首先解析接口上的SPI注解然后拿到SPI注解配置的默认实现类并缓存起来调用loadDirectory从指定的3个配置路径中查找扩展配置文件并放入extensionClasses中路径分别为 /META-INF/dubbo/internal// META-INF/dubbo//META-INF/services/ 这个主要是兼容jdk的spi 返回加载出来的扩展实现类extensionClasses 2.3.3.1.2、ExtensionLoader#loadDirectory 这里根据目录前缀和当前类型的权限定名拼接出来一个文件名例META-INF/dubbo/com.test.Robot获取当前ExtensionLoader对应的classLoader使用类加载器加载文件获取到对应的资源调用loadResource解析资源获取到对应的实现类信息 2.3.3.1.3、ExtensionLoader#loadResource 这里就是对文件资源的解析会一行一行读然后过滤掉注释内容然后解析处实现类的名字和权限定类名调用loadClass加载实现类 2.3.3.1.4、ExtensionLoader#loadResource 首先判断实现类是否是接口的子类不是的话抛出异常判断实现类上面有没有Adaptive注解如果有的话再判断cachedAdaptiveClass是否是null这个cachedAdaptiveClass就是缓存带有Adaptive注解的实现类没有的话就赋值给cachedAdaptiveClass有的话就是不是同一个实现类class不是的话就抛出异常这里主要是为了一个扩展点接口只能有一个Adaptive 放到类上面的实现类。判断是不是包装类这里就是根据这个实现类有没有一个构造器是传入当前类型的如果是那么就说明是包装类就缓存到cachedWrapperClasses中判断name是否为空如果是空的话就调用findAnnotationName获取name这里主要是兼容jdk的spi因为dubbo的spi是 名称实现类的权限定名jdk直接是实现类的权限定名这里是兼容一下。如果有name的话再从实现类上获取Activate注解如果上面有标注这个注解通过cachedActivates缓存起来接着就是遍历分割完的names如果cachedNames 不包含 实现类class 的话就put进去缓存起来如果extensionClasses中没有当前name的class就put进去缓存起来如果有了的话就要判断两个class是否相等不相等话就要抛出异常了因为同一个扩展点接口不允许有相同name的扩展点实现类的出现。 这里判断是不是wrapper就是根据这个实现类有没有一个构造器是传入当前类型的。 主要就是判断有没有Extension注解如果没有的话就要拿实现类的类名然后判断实现类类名是否是以接口名为结尾的如果是的话截取下要前面那块如果不是以接口名为结尾的就返回实现类的名字如果有Extension注解就直接拿注解里面的value值,这里主要是兼容jdk spi。 最后全部解析完成后extensionClasses中放的就是配置文件中name作为key然后实现类作为value的map 2.3.3.2、ExtensionLoader#injectExtension 上面已经解析配置文件获取对应扩展名的扩展实现类并创建出对应的实例然后会掉这个方法对创建出来的实例的属性进行依赖注入 遍历实现类的所有方法然后判断如果方法是set方法并且只有一个参数方法类型是public这样才能帮你自动注入如果方法上标注了DisableInject也不进行自动注入获取参数的类型并截取set方法中除了set的剩余字符串调用objectFactory#getExtension获取指定类型的实现这里objectFactory一般是AdaptiveExtensionFactory这样获取到具体的实现并通过反射设置进去。 2.3.3.2.1、AdaptiveExtensionFactory#getExtension 根据扩展点类型获取具体实现类,这里也是根据ExtensionLoader获取支持的扩展实现然后遍历支持的ExtensionFactory获取对应的实现类这里ExtensionFactory有两个具体实现一个是SpiExtensionFactory一个是SpringExtensionFactory 2.3.3.2.2、SpiExtensionFactory#getExtension 这里首先判断要注入的class是否类上面标注了SPI注解如果标注了则获取对应类型的ExtensionLoader调用ExtensionLoader#getAdaptiveExtension获取适配器实现并返回 2.3.3.2.3、SpiExtensionFactory#getExtension 这里首先就是根据name去spring容器中获取对应的bean返回如果根据name获取不到bean则再根据对应的class类型去获取bean返回 2.3.4、ExtensionLoader#getAdaptiveExtension 在之前我们的示例中我们会调用getAdaptiveExtension方法获取自适应的扩展实现方法逻辑大致如下先从缓存中获取自适应的实例如果缓存中没有则会调用createAdaptiveExtension方法创建一个自适应实例并返回。 2.3.4.1、ExtensionLoader#createAdaptiveExtension 这里首先调用getAdaptiveExtensionClass获取自适应扩展实现的class然后通过反射创建实例调用injectExtension方法对这个创建出来的实例进行依赖注入 2.3.4.2、ExtensionLoader#getAdaptiveExtensionClass 首先是获取所有的扩展实现类class之前咱们分析过会将实现类上带有Adaptive注解的缓存到cachedAdaptiveClass 这个成员中。那如果没有实现类上带有Adaptive注解的时候就要通过createAdaptiveExtensionClass来创建自适应扩展实现类了。 2.3.4.3、ExtensionLoader#createAdaptiveExtensionClass 首先是通过createAdaptiveExtensionClassCode方法来拼装成自适应实现类的代码接着就是使用spi获取编译器然后进行编译加载返回自适应实现类的class对象。 2.3.4.3、ExtensionLoader#createAdaptiveExtensionClassCode 首先遍历接口的所有方法判断上面有没有标注Adaptive注解一个没有就抛出异常只要有一个方法上有注解就继续执行拼装packageimport然后就是类名(接口名$Adaptive)然后实现一下接口遍历方法判断方法上是否有Adaptive注解如果没有将抛出异常的代码追加到code上如果有Adaptive注解找出URL参数在参数列表的位置如果有URL参数就拼装成判断是否是null如果是null就抛出异常然后设置到本地变量。如果没有URL就遍历参数类型里面有get方法并且get方法不是静态没有参数返回值是URL类型的没有找到这么个条件的参数的时候就会抛出异常 如果找到判断这个参数不是null参数获取的URL不是null然后URL设置到本地变量url中。接着获取Adaptive 注解值如果没有值就那class 名字来 如果参数有Invocation类型的然后生成判断null的代码与String methodName arg0.getMethodName()并设置标志hasInvocation为true.接着就是遍历Adaptive 上面value数组这块主要是实现通过url来获取配置参数的值这个值就是对应扩展实现类的name判断extName如果是null的话就要抛出异常接着就是通过getExtensionLoader(当前扩展接口).getExtension(extName)来获取扩展实现类对象然后再通过这个实现类对象调用自己对应的这个方法. private String createAdaptiveExtensionClassCode() {StringBuilder codeBuilder new StringBuilder();Method[] methods type.getMethods();boolean hasAdaptiveAnnotation false;//查找方法上面有没有Adaptive注解for (Method m : methods) {if (m.isAnnotationPresent(Adaptive.class)) {hasAdaptiveAnnotation true;break;}}// no need to generate adaptive class since theres no adaptive method found.if (!hasAdaptiveAnnotation)throw new IllegalStateException(No adaptive method on extension type.getName() , refuse to create the adaptive class!);codeBuilder.append(package ).append(type.getPackage().getName()).append(;);codeBuilder.append(\nimport ).append(ExtensionLoader.class.getName()).append(;);codeBuilder.append(\npublic class ).append(type.getSimpleName()).append($Adaptive).append( implements ).append(type.getCanonicalName()).append( {);for (Method method : methods) {//返回值Class? rt method.getReturnType();//参数类型Class?[] pts method.getParameterTypes();//异常Class?[] ets method.getExceptionTypes();Adaptive adaptiveAnnotation method.getAnnotation(Adaptive.class);StringBuilder code new StringBuilder(512);if (adaptiveAnnotation null) {code.append(throw new UnsupportedOperationException(\method ).append(method.toString()).append( of interface ).append(type.getName()).append( is not adaptive method!\););} else {int urlTypeIndex -1;//查找参数列表中有没有URLfor (int i 0; i pts.length; i) {if (pts[i].equals(URL.class)) {urlTypeIndex i;break;}}// found parameter in URL type//说明有if (urlTypeIndex ! -1) {// Null Point checkString s String.format(\nif (arg%d null) throw new IllegalArgumentException(\url null\);,urlTypeIndex);code.append(s);s String.format(\n%s url arg%d;, URL.class.getName(), urlTypeIndex);code.append(s);}// did not find parameter in URL typeelse { //没有url参数的String attribMethod null;// find URL getter methodLBL_PTS:for (int i 0; i pts.length; i) {//查找参数里面 有get方法并且返回值是URL的Method[] ms pts[i].getMethods();for (Method m : ms) {String name m.getName();if ((name.startsWith(get) || name.length() 3) Modifier.isPublic(m.getModifiers()) !Modifier.isStatic(m.getModifiers()) m.getParameterTypes().length 0 m.getReturnType() URL.class) {urlTypeIndex i;attribMethod name;break LBL_PTS;}}}if (attribMethod null) {throw new IllegalStateException(fail to create adaptive class for interface type.getName() : not found url parameter or url attribute in parameters of method method.getName());}// Null point check//验证有get方法返回值是URL的参数是否为null然后get到的URL是否是nullString s String.format(\nif (arg%d null) throw new IllegalArgumentException(\%s argument null\);,urlTypeIndex, pts[urlTypeIndex].getName());code.append(s);s String.format(\nif (arg%d.%s() null) throw new IllegalArgumentException(\%s argument %s() null\);,urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);code.append(s);//如果参数获取到的URL不是null则设置URL到本地变量url中s String.format(%s url arg%d.%s();, URL.class.getName(), urlTypeIndex, attribMethod);code.append(s);}//接着遍历Adaptive注解上面的value数组这块主要是通过url来获取配置参数的值这个值就是对应扩展实现类的//name//判断extName如果是null的话就要抛出异常接着就是通过getExtensionLoader(当前扩展接口).getExtension(extName)// 来获取扩展实现类对象然后再通过这个实现类对象调用自己对应的这个方法。String[] value adaptiveAnnotation.value();// value is not set, use the value generated from class name as the keyif (value.length 0) { //没有值char[] charArray type.getSimpleName().toCharArray();StringBuilder sb new StringBuilder(128);for (int i 0; i charArray.length; i) {if (Character.isUpperCase(charArray[i])) {//是大写字母if (i ! 0) {sb.append(.);}sb.append(Character.toLowerCase(charArray[i]));} else {sb.append(charArray[i]);}}value new String[] {sb.toString()};}boolean hasInvocation false;for (int i 0; i pts.length; i) {if (pts[i].getName().equals(com.alibaba.dubbo.rpc.Invocation)) {// Null Point checkString s String.format(\nif (arg%d null) throw new IllegalArgumentException(\invocation null\);, i);code.append(s);s String.format(\nString methodName arg%d.getMethodName();, i);code.append(s);hasInvocation true;break;}}String defaultExtName cachedDefaultName;String getNameCode null;for (int i value.length - 1; i 0; --i) {if (i value.length - 1) {if (null ! defaultExtName) {if (!protocol.equals(value[i]))if (hasInvocation)getNameCode String.format(url.getMethodParameter(methodName, \%s\, \%s\), value[i], defaultExtName);elsegetNameCode String.format(url.getParameter(\%s\, \%s\), value[i], defaultExtName);elsegetNameCode String.format(( url.getProtocol() null ? \%s\ : url.getProtocol() ), defaultExtName);} else {if (!protocol.equals(value[i]))if (hasInvocation)getNameCode String.format(url.getMethodParameter(methodName, \%s\, \%s\), value[i], defaultExtName);elsegetNameCode String.format(url.getParameter(\%s\), value[i]);elsegetNameCode url.getProtocol();}} else {if (!protocol.equals(value[i]))if (hasInvocation)getNameCode String.format(url.getMethodParameter(methodName, \%s\, \%s\), value[i], defaultExtName);elsegetNameCode String.format(url.getParameter(\%s\, %s), value[i], getNameCode);elsegetNameCode String.format(url.getProtocol() null ? (%s) : url.getProtocol(), getNameCode);}}code.append(\nString extName ).append(getNameCode).append(;);// check extName null?String s String.format(\nif(extName null) throw new IllegalStateException(\Fail to get extension(%s) name from url(\ url.toString() \) use keys(%s)\);,type.getName(), Arrays.toString(value));code.append(s);s String.format(\n%s extension (%s)%s.getExtensionLoader(%s.class).getExtension(extName);,type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());code.append(s);// return statementif (!rt.equals(void.class)) {code.append(\nreturn );}s String.format(extension.%s(, method.getName());code.append(s);for (int i 0; i pts.length; i) {if (i ! 0)code.append(, );code.append(arg).append(i);}code.append(););}codeBuilder.append(\npublic ).append(rt.getCanonicalName()).append( ).append(method.getName()).append(();for (int i 0; i pts.length; i) {if (i 0) {codeBuilder.append(, );}codeBuilder.append(pts[i].getCanonicalName());codeBuilder.append( );codeBuilder.append(arg).append(i);}codeBuilder.append());if (ets.length 0) {codeBuilder.append( throws );for (int i 0; i ets.length; i) {if (i 0) {codeBuilder.append(, );}codeBuilder.append(ets[i].getCanonicalName());}}codeBuilder.append( {);codeBuilder.append(code.toString());codeBuilder.append(\n});}codeBuilder.append(\n});if (logger.isDebugEnabled()) {logger.debug(codeBuilder.toString());}return codeBuilder.toString();}这个自适应就是根据接口自己实现一个实现类然后这个实现类是能够根据Adaptive 配置的参数值然后去URL中获取对应的值然后再根据这个值使用spi获取扩展实现类最后调用这个实现类的对应方法。 2.3.5、ExtensionLoader#getAdaptiveExtension 在之前我们的示例中我们会调用getActivateExtension方法获取自动激活的扩展实现方法逻辑大致如下 首先将values放到names这个list中然后判断如果names中没有-default就继续执行这里-default是用户自己设置表示不使用这些配置的key调用getExtensionClasses加载扩展点的所有实现类这个之前剖析过然后遍历cachedActivates这个map这个是我们在执行getExtensionClasses的时候缓存的根据注解中的配置判断group是否一致如果是这个group再判断names中有没有包含这个names然后判断names中有没有配置-name-name表示不激活该扩展实现再然后就是判断注解中的value在url中有对应参数同时满足这些条件说明这个扩展实现是满足的添加到exts集合中对exts集合进行排序最后再遍历一下names如果name没有-开头或者是names中没有-xxx 然后就通过name获取到对应的扩展点实现添加到usrs这个list中最后判断usrs这个list不是空的话就将usrs元素扔到exts中然后return exts。
http://www.w-s-a.com/news/536745/

相关文章:

  • 天猫优惠券网站怎么做的网络连接
  • 保定网站建设多少钱公司网页网站建设+ppt模板下载
  • 用户上传商品网站用什么做建设跳转公积金网站
  • 买程序的网站上海市网站建设公司
  • 南通网站建设排名公司哪家好wordpress网站图片迁移
  • 河南省汝州文明建设门户网站博客网站建设源码
  • 单位建设网站的请示手机移动端网站案例
  • 国内做网站的企业网站结构有哪些类型
  • 南通网站建设制作公司苏州好的网站公司名称
  • 咸阳做网站开发公司哪家好珠海公司制作网站
  • 深圳网站建设好不好医疗网站前置审批
  • 做ic什么网站好安溪网站建设
  • 网站建设 慕课企业文化标语经典
  • 做短视频的网站都有哪些简约 时尚 高端 网站建设
  • 浦口区网站建设售后服务建设一个网站多少钱
  • 做个小网站大概多少钱广州h5网站
  • 360免费建站视频wordpress标签显示图片
  • 创建简易个人网站国外做网站被动收入
  • 轻定制网站建设网页培训哪个机构好
  • 青岛海诚互联做网站好吗计算机软件开发培训机构
  • 德钦网站建设如何在网站上做用工登记
  • 创意品牌网站云服务
  • 个人备案网站可以做商城展示如何制作网页二维码
  • 网站建设php教程视频百度seo 站长工具
  • 外包小程序两个相同的网站对做优化有帮助
  • 网站备案主体修改wordpress 导航图片
  • 怎么建设网站数据库用vs代码做网站
  • 运营企业网站怎么赚钱动漫制作专业概念
  • 宜春网站建设推广网络推广工作好干吗
  • 网站程序0day平顶山市做网站