Dubbo的SPI原理

女爷i 2023-02-27 08:18 111阅读 0赞

前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类

正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。

1、SPI 实例

1.1、Java SPI

1.1.1、接口**Robot**

  1. public interface Robot {
  2. void sayHello();
  3. }

1.1.1.1、实现类OptimusPrime

  1. @Slf4j
  2. public class OptimusPrime implements Robot {
  3. @Override
  4. public void sayHello() {
  5. log.info("Hello, I am Optimus Prime.");
  6. }
  7. }

1.1.1.2、实现类Bumblebee

  1. @Slf4j
  2. public class Bumblebee implements Robot {
  3. @Override
  4. public void sayHello() {
  5. log.info("Hello, I am Bumblebee.");
  6. }
  7. }

1.1.2、 接口全限名配置文件

resources -> META-INFO ->services

  1. com.healerjean.proj.study.spi.OptimusPrime
  2. com.healerjean.proj.study.spi.Bumblebee

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MTOIpGAu-1594897494549)(https://raw.githubusercontent.com/HealerJean/HealerJean.github.io/master/blogImages/image-20200627155645060.png)\]

1.1.3、Main方法测试

  1. @Slf4j
  2. public class JavaSPITest {
  3. @Test
  4. public void sayHello() {
  5. ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class);
  6. log.info("Java SPI--------");
  7. serviceLoader.forEach(Robot::sayHello);
  8. }
  9. }

1.1.3.1、控制台日志

  1. 2020-06-27 15:58:02 INFO -[ ]- Java SPI-------- com.healerjean.proj.study.spi.java.JavaSPITest.sayHello[21]
  2. 2020-06-27 15:58:02 INFO -[ ]- Hello, I am Optimus Prime. com.healerjean.proj.study.spi.OptimusPrime.sayHello[16]
  3. 2020-06-27 15:58:02 INFO -[ ]- Hello, I am Bumblebee. com.healerjean.proj.study.spi.Bumblebee.sayHello[17]

1.2、Dubbo SPI

继续使用上面的代码,对其进行改动一点点

1.2.1、接口添加注解@SPI

  1. @SPI
  2. public interface Robot {
  3. void sayHello();
  4. }

1.2.2、配置文件

dubbo配置文件一般在dubbo文件夹中,但是其实通过后面的源码我们也可以知道,不一定非要在这个文件夹中,其他文件夹也是可以的

  1. optimusPrime = com.healerjean.proj.study.spi.OptimusPrime
  2. bumblebee = com.healerjean.proj.study.spi.Bumblebee

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6jkaSvC-1594897494551)(https://raw.githubusercontent.com/HealerJean/HealerJean.github.io/master/blogImages/image-20200627160249742.png)\]

1.2.3、Main方法启测试

  1. @Slf4j
  2. public class DubboSPITest {
  3. @Test
  4. public void sayHello() {
  5. ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
  6. log.info("dubbo SPI--------");
  7. log.info("----------------------------");
  8. log.info("从配置文件中获取--------");
  9. Robot optimusPrime = extensionLoader.getExtension("optimusPrime");
  10. optimusPrime.sayHello();
  11. Robot bumblebee = extensionLoader.getExtension("bumblebee");
  12. bumblebee.sayHello();
  13. log.info("----------------------------");
  14. log.info("{}", extensionLoader.getSupportedExtensions());
  15. }

1.2.3.1、控制台日志

  1. 2020-06-27 16:04:19 INFO -[ ]- using logger: com.alibaba.dubbo.common.logger.slf4j.Slf4jLoggerAdapter com.alibaba.dubbo.common.logger.LoggerFactory.[]
  2. 2020-06-27 16:04:19 INFO -[ ]- dubbo SPI-------- com.healerjean.proj.study.spi.dubbo.DubboSPITest.sayHello[21]
  3. 2020-06-27 16:04:19 INFO -[ ]- ---------------------------- com.healerjean.proj.study.spi.dubbo.DubboSPITest.sayHello[22]
  4. 2020-06-27 16:04:19 INFO -[ ]- 从配置文件中获取-------- com.healerjean.proj.study.spi.dubbo.DubboSPITest.sayHello[23]
  5. 2020-06-27 16:04:20 INFO -[ ]- Hello, I am Optimus Prime. com.healerjean.proj.study.spi.OptimusPrime.sayHello[16]
  6. 2020-06-27 16:04:20 INFO -[ ]- Hello, I am Bumblebee. com.healerjean.proj.study.spi.Bumblebee.sayHello[17]
  7. 2020-06-27 16:04:20 INFO -[ ]- ---------------------------- com.healerjean.proj.study.spi.dubbo.DubboSPITest.sayHello[28]
  8. 2020-06-27 16:04:20 INFO -[ ]- ["bumblebee","optimusPrime"] com.healerjean.proj.study.spi.dubbo.DubboSPITest.sayHello[30]

1.3、@Adaptive 注解使用

在类,以及方法上调用。定义了 注解的方法,参数列表中一定要有类型为 URL 的参数。

value 是个字符数组,通过该属性从 URL 中获取扩展名,来决定使用哪个扩展。分为几种情况:

1.设置了 value,且从 URL 中找到了对应的扩展名,则使用该扩展;

2.设置了 value,但从 URL 中找不到扩展名,则使用默认的扩展,即@SPI 中配置的 value,还是找不到则抛出异常;

3.未设置 value,则根据接口名生成 value,比如接口 Animal生成 value = “animal”。

  1. @Documented
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Target({ ElementType.TYPE, ElementType.METHOD})
  4. public @interface Adaptive {
  5. }

1.3.1、实例说明

1.3.1.1、实例1

@SPI注解中有value值

1.3.1.1.1、示例代码

接口

  1. @SPI(value = "adaptiveAnimal")
  2. public interface Animal {
  3. @Adaptive
  4. void call(String msg, URL url);
  5. }

扩展类

  1. @Slf4j
  2. public class AdaptiveAnimal implements Animal {
  3. @Override
  4. public void call(String msg, URL url) {
  5. log.info("我是适配动物,发出叫声:{}", msg);
  6. }
  7. }
  8. @Slf4j
  9. public class Cat implements Animal {
  10. @Override
  11. public void call(String msg, URL url) {
  12. log.info("我是猫,发出叫声: {},", msg);
  13. }
  14. }
  15. @Slf4j
  16. public class Dog implements Animal {
  17. @Override
  18. public void call(String msg, URL url) {
  19. log.info("我是狗,发出叫声: {},", msg);
  20. }
  21. }
1.3.1.1.2、启动测试
  1. /** * 1、 @SPI注解中有value值,URL中没有具体的值 * 2、@SPI注解中有value值,URL中也有具体的值 */
  2. @Test
  3. public void test1() {
  4. ExtensionLoader<Animal> annoimalExtensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
  5. Animal adaptiveExtension = annoimalExtensionLoader.getAdaptiveExtension();
  6. //1、 @SPI注解中有value值,URL中没有具体的值
  7. URL url = URL.valueOf("test://localhost/test");
  8. adaptiveExtension.call("哒哒哒", url); //我是适配动物,发出叫声:哒哒哒
  9. //2、@SPI注解中有value值,URL中也有具体的值
  10. url = URL.valueOf("test://localhost/test?animal=cat");
  11. adaptiveExtension.call("喵喵喵", url); // 我是猫,发出叫声: 喵喵喵
  12. }

控制台日志

  1. 我是适配动物,发出叫声:哒哒哒
  2. 我是猫,发出叫声: 喵喵喵
1.3.1.1.3、中间dubbo生成的适配扩展类
  1. package com.healerjean.proj.study.spi;
  2. import com.alibaba.dubbo.common.extension.ExtensionLoader;
  3. public class Animal$Adaptive implements com.healerjean.proj.study.spi.Animal {
  4. public void call(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
  5. if (arg1 == null) throw new IllegalArgumentException("url == null");
  6. com.alibaba.dubbo.common.URL url = arg1;
  7. //获取animal,如果获取不到则选择adaptiveAnimal
  8. String extName = url.getParameter("animal", "adaptiveAnimal");
  9. if (extName == null)
  10. throw new IllegalStateException("Fail to get extension(com.healerjean.proj.study.spi.Animal) name from url(" + url.toString() + ") use keys([animal])");
  11. com.healerjean.proj.study.spi.Animal extension = (com.healerjean.proj.study.spi.Animal)
  12. ExtensionLoader.getExtensionLoader(com.healerjean.proj.study.spi.Animal.class).getExtension(extName);
  13. extension.call(arg0, arg1);
  14. }
  15. }

1.3.1.2、实例2

@SPI注解中有value(dog)值,URL中也有具体的值(cat),实现类AdaptiveAnimal上有@Adaptive注解

1.3.1.2.1、示例代码

接口

  1. @SPI(value = "dog")
  2. public interface Animal {
  3. @Adaptive
  4. void call(String msg, URL url);
  5. }

扩展类

  1. @Adaptive
  2. @Slf4j
  3. public class AdaptiveAnimal implements Animal {
  4. @Override
  5. public void call(String msg, URL url) {
  6. log.info("我是适配动物,发出叫声:{}", msg);
  7. }
  8. }
  9. @Slf4j
  10. public class Cat implements Animal {
  11. @Override
  12. public void call(String msg, URL url) {
  13. log.info("我是猫,发出叫声: {},", msg);
  14. }
  15. }
  16. @Slf4j
  17. public class Dog implements Animal {
  18. @Override
  19. public void call(String msg, URL url) {
  20. log.info("我是狗,发出叫声: {},", msg);
  21. }
  22. }
1.3.1.3.2、启动测试
  1. @Test
  2. public void test3() {
  3. ExtensionLoader<Animal> annoimalExtensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
  4. Animal adaptiveExtension = annoimalExtensionLoader.getAdaptiveExtension();
  5. URL url = URL.valueOf("test://localhost/test?animal=cat");
  6. adaptiveExtension.call("哒哒哒", url); //我是适配动物,发出叫声:哒哒哒
  7. }

控制台日志:

  1. 我是适配动物,发出叫声:哒哒哒
1.3.1.2.3、中间dubbo不会生成

不会帮我们生成,因为,这个时候使用了注解@Adaptive,则这个类就是适配扩展类,

那如果有多个类给注解了呢,则只会选中一个

1.3.1.4、实例4

@SPI注解中有value值,实现类上没有@Adaptive注解,方法上的@Adaptive注解,注解中的value与链接中的参数的key一致,链接中的key对应的value就是spi中的name,获取相应的实现类。

1.3.1.4.1、实例代码

接口:

  1. @SPI(value = "adaptiveAnimal")
  2. public interface Animal {
  3. @Adaptive(value = "name")
  4. void call(String msg, URL url);
  5. }

扩展类

  1. @Slf4j
  2. public class AdaptiveAnimal implements Animal {
  3. @Override
  4. public void call(String msg, URL url) {
  5. log.info("我是适配动物,发出叫声:{}", msg);
  6. }
  7. }
  8. @Slf4j
  9. public class Dog implements Animal {
  10. @Override
  11. public void call(String msg, URL url) {
  12. log.info("我是狗,发出叫声: {},", msg);
  13. }
  14. }
  15. @Slf4j
  16. public class Cat implements Animal {
  17. @Override
  18. public void call(String msg, URL url) {
  19. log.info("我是猫,发出叫声: {},", msg);
  20. }
  21. }
1.3.1.4.2、启动测试
  1. @Test
  2. public void test4() {
  3. ExtensionLoader<Animal> annoimalExtensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
  4. Animal adaptiveExtension = annoimalExtensionLoader.getAdaptiveExtension();
  5. URL url = URL.valueOf("test://localhost/test?name=dog");
  6. adaptiveExtension.call("汪汪汪", url); //我是狗,发出叫声: 汪汪汪
  7. }

控制台日志:

  1. 我是狗,发出叫声: 汪汪汪
1.3.1.3.3、中间dubbo生成的适配扩展类
  1. package com.healerjean.proj.study.spi;
  2. import com.alibaba.dubbo.common.extension.ExtensionLoader;
  3. public class Animal$Adaptive implements com.healerjean.proj.study.spi.Animal {
  4. public void call(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
  5. if (arg1 == null) throw new IllegalArgumentException("url == null");
  6. com.alibaba.dubbo.common.URL url = arg1;
  7. //获取url路径中key为name的值,获取不到的话,就选中adaptiveAnimal
  8. String extName = url.getParameter("name", "adaptiveAnimal");
  9. if (extName == null) throw new IllegalStateException("Fail to get extension(com.healerjean.proj.study.spi.Animal) name from url(" + url.toString() + ") use keys([name])");
  10. com.healerjean.proj.study.spi.Animal extension = (com.healerjean.proj.study.spi.Animal) ExtensionLoader.getExtensionLoader(com.healerjean.proj.study.spi.Animal.class).getExtension(extName);
  11. extension.call(arg0, arg1);
  12. }
  13. }

1.3.2、归纳总结

1、在类上加上@Adaptive注解的类,是最为明确的创建对应类型Adaptive类。所以他优先级最高

2、@SPI注解中的value是默认值,如果通过URL获取不到关于取哪个类作为Adaptive类的话,就使用这个默认值,当然如果URL中可以获取到,就用URL中的。

3、方法上的@Adaptive注解,注解中的value与链接中的参数的key一致,链接中的key对应的value就是spi中的name,获取相应的实现类。

1.4、@Activate

1、根据loader.getActivateExtension中group和搜索到此类型的实例进行比较,如果group能匹配到,就是我们选择的,也就是在此条件下需要激活的

2、@Activate中的value是参数是第二层过滤参数(第一层是通过group),在group校验通过的前提下,如果URL中的参数(k)与值(v)中的参数名同@Activate中的value值一致或者包含,那么才会被选中。相当于加入了value后,条件更为苛刻点,需要URL中有此参数并且,参数必须有值。

3、@Activateorder参数对于同一个类型的多个扩展来说,order值越小,优先级越高。

接着上面的代码

  1. @Activate(group = "default_group", value = "valueAc")
  2. @Slf4j
  3. public class Dog implements Animal {
  4. @Override
  5. public void call(String msg, URL url) {
  6. log.info("我是狗,发出叫声: {},", msg);
  7. }
  8. }
  9. @Test
  10. public void getActive() {
  11. ExtensionLoader<Animal> annoimalExtensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
  12. URL url = URL.valueOf("test://localhost/test");
  13. List<Animal> list = annoimalExtensionLoader.getActivateExtension(url, new String[]{ }, "default_group");
  14. list.stream().forEach(System.out::println); //null
  15. log.info("-----------------");
  16. url = URL.valueOf("test://localhost/test?valueAc=fasdjafjdklj");
  17. list = annoimalExtensionLoader.getActivateExtension(url, new String[]{ }, "default_group");
  18. list.stream().forEach(System.out::println); //com.healerjean.proj.study.spi.Dog@59fd97a8
  19. }

1.4、WrapperClass

如果检测到是一个包装类,则不会放入 cachedNamescachedClasses中,那么怎么才符合条件呢,就是说有一个构造器,传入的参数是接口

  1. //包装类集合
  2. private Set<Class<?>> cachedWrapperClasses;
  3. private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
  4. private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
  5. private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
  6. if (!type.isAssignableFrom(clazz)) {
  7. throw new IllegalStateException("Error when load extension class(interface: " +
  8. type + ", class line: " + clazz.getName() + "), class "
  9. + clazz.getName() + "is not subtype of interface.");
  10. }
  11. if (clazz.isAnnotationPresent(Adaptive.class)) {
  12. if (cachedAdaptiveClass == null) {
  13. cachedAdaptiveClass = clazz;
  14. } else if (!cachedAdaptiveClass.equals(clazz)) {
  15. throw new IllegalStateException("More than 1 adaptive class found: "
  16. + cachedAdaptiveClass.getClass().getName()
  17. + ", " + clazz.getClass().getName());
  18. }
  19. } else if (isWrapperClass(clazz)) {
  20. //如果是一个包装类,则放到 cachedWrapperClasses中去
  21. Set<Class<?>> wrappers = cachedWrapperClasses;
  22. if (wrappers == null) {
  23. cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
  24. wrappers = cachedWrapperClasses;
  25. }
  26. wrappers.add(clazz);
  27. } else {
  28. clazz.getConstructor();
  29. if (name == null || name.length() == 0) {
  30. name = findAnnotationName(clazz);
  31. if (name == null || name.length() == 0) {
  32. if (clazz.getSimpleName().length() > type.getSimpleName().length()
  33. && clazz.getSimpleName().endsWith(type.getSimpleName())) {
  34. name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
  35. } else {
  36. throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
  37. }
  38. }
  39. }
  40. String[] names = NAME_SEPARATOR.split(name);
  41. if (names != null && names.length > 0) {
  42. Activate activate = clazz.getAnnotation(Activate.class);
  43. if (activate != null) {
  44. cachedActivates.put(names[0], activate);
  45. }
  46. for (String n : names) {
  47. if (!cachedNames.containsKey(clazz)) {
  48. cachedNames.put(clazz, n);
  49. }
  50. Class<?> c = extensionClasses.get(n);
  51. if (c == null) {
  52. extensionClasses.put(n, clazz);
  53. } else if (c != clazz) {
  54. throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
  55. }
  56. }
  57. }
  58. }
  59. }
  60. private boolean isWrapperClass(Class<?> clazz) {
  61. try {
  62. clazz.getConstructor(type);
  63. return true;
  64. } catch (NoSuchMethodException e) {
  65. return false;
  66. }
  67. }

1.4.1、实例说明

1.4.1.1、示例代码

接口

  1. @SPI
  2. public interface Animal {
  3. @Adaptive(value = "name")
  4. void call(String msg, URL url);
  5. }

包装类 CAT ,扩展类DOG

  1. @Slf4j
  2. public class Cat implements Animal {
  3. private Animal animal;
  4. public Cat() {
  5. }
  6. public Cat(Animal animal) {
  7. animal = animal;
  8. }
  9. @Override
  10. public void call(String msg, URL url) {
  11. log.info("我是猫,发出叫声: {},", msg);
  12. }
  13. }
  14. public class Dog implements Animal {
  15. @Override
  16. public void call(String msg, URL url) {
  17. log.info("我是狗,发出叫声: {},", msg);
  18. }
  19. }
  20. @Test
  21. public void load() {
  22. ExtensionLoader<Animal> annoimalExtensionLoader = ExtensionLoader.getExtensionLoader(Animal.class);
  23. log.info("#######################################");
  24. Animal dog = annoimalExtensionLoader.getExtension("dog");
  25. dog.call("旺旺旺", null); //我是猫,发出叫声: 旺旺旺 ,说明返回的是cat扩展类,而不是dog,具体看下面的代码分析
  26. Animal cat = annoimalExtensionLoader.getExtension("cat"); //抛出异常,不存在该扩展类,就是说
  27. cat.call("我是一只猫", null);
  28. log.info("#######################################");
  29. }
  30. private T createExtension(String name) {
  31. Class<?> clazz = getExtensionClasses().get(name);
  32. if (clazz == null) {
  33. throw findException(name);
  34. }
  35. try {
  36. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  37. if (instance == null) {
  38. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  39. instance = (T) EXTENSION_INSTANCES.get(clazz);
  40. }
  41. injectExtension(instance);
  42. //如果发现包装类的话,则返回的是cat,cat构造器中传入的是dog
  43. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  44. if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
  45. for (Class<?> wrapperClass : wrapperClasses) {
  46. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  47. }
  48. }
  49. return instance;
  50. } catch (Throwable t) {
  51. throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
  52. type + ") could not be instantiated: " + t.getMessage(), t);
  53. }
  54. }

2、SPI源码分析

2.1、获取扩展点加载ExtensionLoader

所有扩展必须加上@SPI注解才能通过ExtensionLoader加载。对于一个扩展点只会加载一次,生成一个ExtensionLoader。通过ExtensionLoader.getExtensionLoader(class type)传入一个spi扩展返回一个ExtensionLoader实例。

  1. ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);
  2. // static 变量,所有的扩展点都只会加载一次,然后就会放到这里。相当于缓存,type为key的值,扩展点就是value
  3. private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
  4. @SuppressWarnings("unchecked")
  5. public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  6. if (type == null)
  7. throw new IllegalArgumentException("Extension type == null");
  8. if (!type.isInterface()) {
  9. throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
  10. }
  11. //必须加SPI注解
  12. if (!withExtensionAnnotation(type)) {
  13. throw new IllegalArgumentException("Extension type(" + type +
  14. ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
  15. }
  16. //从缓存中取,如果缓存中没有 则,new一个扩展点加载
  17. ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  18. if (loader == null) {
  19. //如果缓存中没有 则,new一个扩展点加载,并将它放到缓存中去,这个type,就是key的值
  20. EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
  21. loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  22. }
  23. return loader;
  24. }
  25. //验证 是否有@SPI注解
  26. private static <T> boolean withExtensionAnnotation(Class<T> type) {
  27. return type.isAnnotationPresent(SPI.class);
  28. }

首次进入的话,typeRobot.class肯定不等扩展点工厂,然后通过3元表达式可以看到,我们需要先获取扩展点工厂加载(ExtensionFactory),,这样的话,扩展点工厂的属性objectFactory,就是null,而我们传入的Robot.class,中的属性objectFactory,则是通过扩展点工厂获取的适配扩展点工厂,

接着我们看如果获取适配加载点,以及适配加载点是什么getAdaptiveExtension()

  1. private final Class<?> type;
  2. private final ExtensionFactory objectFactory;
  3. private ExtensionLoader(Class<?> type) {
  4. this.type = type;
  5. objectFactory = (type == ExtensionFactory.class ?
  6. null :
  7. ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  8. }

2.1.1、获取适配扩展点

Dubbo中的扩展点均有多个实现,而框架设计原则又让我们针对接口编程而不是实现,这就需要在运行期才能决定具体使用哪个扩展实现类。Dubbo提供了Adpative注解,让我们自行决定究竟是自己提供扩展的适配还是由Dubbo来帮我们生成动态适配。后面会给出2个自定义扩展实现,一个是我们自定义适配,另一个是Dubbo提供动态适配。

  1. 适配扩展点
  2. adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
  3. spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
  4. spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
  5. @SPI
  6. public interface ExtensionFactory {
  7. <T> T getExtension(Class<T> type, String name);
  8. }
  9. @Adaptive
  10. public class AdaptiveExtensionFactory implements ExtensionFactory {
  11. private final List<ExtensionFactory> factories;
  12. public AdaptiveExtensionFactory() {
  13. ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
  14. List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
  15. for (String name : loader.getSupportedExtensions()) {
  16. list.add(loader.getExtension(name));
  17. }
  18. factories = Collections.unmodifiableList(list);
  19. }
  20. @Override
  21. public <T> T getExtension(Class<T> type, String name) {
  22. for (ExtensionFactory factory : factories) {
  23. T extension = factory.getExtension(type, name);
  24. if (extension != null) {
  25. return extension;
  26. }
  27. }
  28. return null;
  29. }
  30. }
  31. public class SpiExtensionFactory implements ExtensionFactory {
  32. @Override
  33. public <T> T getExtension(Class<T> type, String name) {
  34. if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
  35. ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
  36. if (!loader.getSupportedExtensions().isEmpty()) {
  37. return loader.getAdaptiveExtension();
  38. }
  39. }
  40. return null;
  41. }
  42. }
  43. public class SpringExtensionFactory implements ExtensionFactory {
  44. private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
  45. public static void addApplicationContext(ApplicationContext context) {
  46. contexts.add(context);
  47. }
  48. public static void removeApplicationContext(ApplicationContext context) {
  49. contexts.remove(context);
  50. }
  51. @Override
  52. @SuppressWarnings("unchecked")
  53. public <T> T getExtension(Class<T> type, String name) {
  54. for (ApplicationContext context : contexts) {
  55. if (context.containsBean(name)) {
  56. Object bean = context.getBean(name);
  57. if (type.isInstance(bean)) {
  58. return (T) bean;
  59. }
  60. }
  61. }
  62. return null;
  63. }
  64. }
  65. public class Holder<T> {
  66. private volatile T value;
  67. public void set(T value) {
  68. this.value = value;
  69. }
  70. public T get() {
  71. return value;
  72. }
  73. }
  74. //当前对象中的缓存的适配扩展点
  75. private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
  76. //获取适配扩展点,如果没有的话,就创建,然后放到当前对象的cachedAdaptiveInstance 中去
  77. @SuppressWarnings("unchecked")
  78. public T getAdaptiveExtension() {
  79. //从当前对象 的缓存属性,扩展点实例中获取一个适配扩展点
  80. Object instance = cachedAdaptiveInstance.get();
  81. if (instance == null) {
  82. if (createAdaptiveInstanceError == null) {
  83. synchronized (cachedAdaptiveInstance) {
  84. instance = cachedAdaptiveInstance.get();
  85. if (instance == null) {
  86. try {
  87. // 经过锁流程后还是没有的话,我们就要创建适配扩展点了,创建完成之后,放到当前对象的缓存适配属性cachedAdaptiveInstance中去
  88. instance = createAdaptiveExtension();
  89. cachedAdaptiveInstance.set(instance);
  90. } catch (Throwable t) {
  91. createAdaptiveInstanceError = t;
  92. throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
  93. }
  94. }
  95. }
  96. } else {
  97. throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
  98. }
  99. }
  100. return (T) instance;
  101. }

2.1.1.1、创建适配扩展点

先执行getAdaptiveExtensionClass() 获取一个适配扩展点的calss对象之后,再通过反射实例化一个对象,然后再通过方能发,injectExtension对适配扩展点对象其中的属性进行注入

  1. //创建适配扩展点
  2. @SuppressWarnings("unchecked")
  3. private T createAdaptiveExtension() {
  4. try {
  5. // 先执行getAdaptiveExtensionClass() 获取一个适配扩展点的calss对象之后,再通过反射实例化一个对象,
  6. // 然后再通过方能发,injectExtension对适配扩展点对象其中的属性进行注入
  7. return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  8. } catch (Exception e) {
  9. throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  10. }
  11. }
  12. //当发现扩展点类class的时候,这里就会赋值
  13. private volatile Class<?> cachedAdaptiveClass = null;
  14. private Class<?> getAdaptiveExtensionClass() {
  15. //获取所有的扩展点类class
  16. getExtensionClasses();
  17. //通过上面的一步正常情况下的话,cachedAdaptiveClass 适配扩展点类就存在了
  18. if (cachedAdaptiveClass != null) {
  19. return cachedAdaptiveClass;
  20. }
  21. return cachedAdaptiveClass = createAdaptiveExtensionClass();
  22. }
  23. //从当前对象的的属性 缓存类 中获取所有的扩展点(不包含适配扩展点哦,具体看下面loadExtensionClasses的代码)
  24. private Map<String, Class<?>> getExtensionClasses() {
  25. Map<String, Class<?>> classes = cachedClasses.get();
  26. if (classes == null) {
  27. synchronized (cachedClasses) {
  28. classes = cachedClasses.get();
  29. if (classes == null) {
  30. //加载所所有的扩展点,加载完成之后放到当前对象的属性cachedClasses 中
  31. classes = loadExtensionClasses();
  32. cachedClasses.set(classes);
  33. }
  34. }
  35. }
  36. return classes;
  37. }
  38. private static final String SERVICES_DIRECTORY = "META-INF/services/";
  39. private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
  40. private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
  41. // 加载扩展类class
  42. private Map<String, Class<?>> loadExtensionClasses() {
  43. final SPI defaultAnnotation = type.getAnnotation(SPI.class);
  44. if (defaultAnnotation != null) {
  45. String value = defaultAnnotation.value();
  46. if ((value = value.trim()).length() > 0) {
  47. String[] names = NAME_SEPARATOR.split(value);
  48. if (names.length > 1) {
  49. throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
  50. + ": " + Arrays.toString(names));
  51. }
  52. //如果说@SPI 有 value值,则下面 cachedDefaultName 将来在没有@Adaptive 注解修饰的时候。dubbo帮我们生成适配扩展类的时候用来作为备用选项(当url不存在参数的时候,返回@SPI value所代表的扩展类),
  53. if (names.length == 1) cachedDefaultName = names[0];
  54. }
  55. }
  56. //将来key就是 我们的配置文件中的name,value就是类。而下面这些变量就解释了我上面在啊实例中说的目录的问题,不一定是dubb文件夹中
  57. Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
  58. loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
  59. loadDirectory(extensionClasses, DUBBO_DIRECTORY);
  60. loadDirectory(extensionClasses, SERVICES_DIRECTORY);
  61. return extensionClasses;
  62. }
  63. private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
  64. String fileName = dir + type.getName();
  65. try {
  66. Enumeration<java.net.URL> urls;
  67. ClassLoader classLoader = findClassLoader();
  68. if (classLoader != null) {
  69. urls = classLoader.getResources(fileName);
  70. } else {
  71. urls = ClassLoader.getSystemResources(fileName);
  72. }
  73. if (urls != null) {
  74. while (urls.hasMoreElements()) {
  75. java.net.URL resourceURL = urls.nextElement();
  76. loadResource(extensionClasses, classLoader, resourceURL);
  77. }
  78. }
  79. } catch (Throwable t) {
  80. logger.error("Exception when load extension class(interface: " +
  81. type + ", description file: " + fileName + ").", t);
  82. }
  83. }
  84. private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
  85. try {
  86. BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
  87. try {
  88. String line;
  89. while ((line = reader.readLine()) != null) {
  90. final int ci = line.indexOf('#');
  91. if (ci >= 0) line = line.substring(0, ci);
  92. line = line.trim();
  93. if (line.length() > 0) {
  94. try {
  95. String name = null;
  96. int i = line.indexOf('=');
  97. if (i > 0) {
  98. name = line.substring(0, i).trim();
  99. line = line.substring(i + 1).trim();
  100. }
  101. if (line.length() > 0) {
  102. loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
  103. }
  104. } catch (Throwable t) {
  105. IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
  106. exceptions.put(line, e);
  107. }
  108. }
  109. }
  110. } finally {
  111. reader.close();
  112. }
  113. } catch (Throwable t) {
  114. logger.error("Exception when load extension class(interface: " +
  115. type + ", class file: " + resourceURL + ") in " + resourceURL, t);
  116. }
  117. }
  118. private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
  119. private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
  120. private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
  121. if (!type.isAssignableFrom(clazz)) {
  122. throw new IllegalStateException("Error when load extension class(interface: " +
  123. type + ", class line: " + clazz.getName() + "), class "
  124. + clazz.getName() + "is not subtype of interface.");
  125. }
  126. //如果扩展点类上面的注解有 Adaptive ,则不会放到map中,而是给当前属性 cachedAdaptiveClass 赋值
  127. if (clazz.isAnnotationPresent(Adaptive.class)) {
  128. if (cachedAdaptiveClass == null) {
  129. cachedAdaptiveClass = clazz;
  130. } else if (!cachedAdaptiveClass.equals(clazz)) {
  131. throw new IllegalStateException("More than 1 adaptive class found: "
  132. + cachedAdaptiveClass.getClass().getName()
  133. + ", " + clazz.getClass().getName());
  134. }
  135. } else if (isWrapperClass(clazz)) {
  136. Set<Class<?>> wrappers = cachedWrapperClasses;
  137. if (wrappers == null) {
  138. cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
  139. wrappers = cachedWrapperClasses;
  140. }
  141. wrappers.add(clazz);
  142. } else {
  143. //此处相当于作为一个判断,必须有空构造器才可以
  144. clazz.getConstructor();
  145. if (name == null || name.length() == 0) {
  146. //如果dubbo文件中 没有name,而是直接写了类,则我们通过全类名获取name 比如com.healerjean.proj.study.spi.Dog 返回是 dog
  147. name = findAnnotationName(clazz);
  148. if (name == null || name.length() == 0) {
  149. if (clazz.getSimpleName().length() > type.getSimpleName().length()
  150. && clazz.getSimpleName().endsWith(type.getSimpleName())) {
  151. name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
  152. } else {
  153. throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
  154. }
  155. }
  156. }
  157. String[] names = NAME_SEPARATOR.split(name);
  158. if (names != null && names.length > 0) {
  159. Activate activate = clazz.getAnnotation(Activate.class);
  160. if (activate != null) {
  161. cachedActivates.put(names[0], activate);
  162. }
  163. // 正常情况下,只有一个name
  164. for (String n : names) {
  165. if (!cachedNames.containsKey(clazz)) {
  166. cachedNames.put(clazz, n);
  167. }
  168. Class<?> c = extensionClasses.get(n);
  169. if (c == null) {
  170. extensionClasses.put(n, clazz);
  171. } else if (c != clazz) {
  172. throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
  173. }
  174. }
  175. }
  176. }
  177. }

2.1.1.2、扩展点通过反射进行实例化

  1. @SuppressWarnings("unchecked")
  2. private T createAdaptiveExtension() {
  3. try {
  4. return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  5. } catch (Exception e) {
  6. throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
  7. }
  8. }
  9. @Adaptive
  10. public class AdaptiveExtensionFactory implements ExtensionFactory {
  11. private final List<ExtensionFactory> factories;
  12. public AdaptiveExtensionFactory() {
  13. //执行这个的时候,静态缓存中已经有了扩展点工厂了
  14. ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
  15. List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
  16. // 当前实力缓存中已经有了扩展类的所有属性了,所以这里是从缓存中取出的
  17. for (String name : loader.getSupportedExtensions()) {
  18. //通过扩展点加载,加载所有的扩展点实现类,spi,spring
  19. list.add(loader.getExtension(name));
  20. }
  21. factories = Collections.unmodifiableList(list);
  22. }
  23. @Override
  24. public <T> T getExtension(Class<T> type, String name) {
  25. for (ExtensionFactory factory : factories) {
  26. T extension = factory.getExtension(type, name);
  27. if (extension != null) {
  28. return extension;
  29. }
  30. }
  31. return null;
  32. }
  33. }
  34. //存放当前对象所有的扩展点实现实例
  35. private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
  36. @SuppressWarnings("unchecked")
  37. public T getExtension(String name) {
  38. if (name == null || name.length() == 0)
  39. throw new IllegalArgumentException("Extension name == null");
  40. if ("true".equals(name)) {
  41. return getDefaultExtension();
  42. }
  43. // 从当前对象的缓存实例中取
  44. Holder<Object> holder = cachedInstances.get(name);
  45. if (holder == null) {
  46. cachedInstances.putIfAbsent(name, new Holder<Object>());
  47. holder = cachedInstances.get(name);
  48. }
  49. Object instance = holder.get();
  50. if (instance == null) {
  51. synchronized (holder) {
  52. instance = holder.get();
  53. if (instance == null) {
  54. //获取不到则进行创建
  55. instance = createExtension(name);
  56. holder.set(instance);
  57. }
  58. }
  59. }
  60. return (T) instance;
  61. }
  62. // 扩展点实例所有实例的静态属性,缓存
  63. private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
  64. private T createExtension(String name) {
  65. Class<?> clazz = getExtensionClasses().get(name);
  66. if (clazz == null) {
  67. throw findException(name);
  68. }
  69. try {
  70. //通过缓存中取,娶不到,就通过反射实例化
  71. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  72. if (instance == null) {
  73. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  74. instance = (T) EXTENSION_INSTANCES.get(clazz);
  75. }
  76. //对属性进行注入
  77. injectExtension(instance);
  78. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  79. if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
  80. for (Class<?> wrapperClass : wrapperClasses) {
  81. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  82. }
  83. }
  84. return instance;
  85. } catch (Throwable t) {
  86. throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
  87. type + ") could not be instantiated: " + t.getMessage(), t);
  88. }
  89. }
  90. private T injectExtension(T instance) {
  91. try {
  92. if (objectFactory != null) {
  93. for (Method method : instance.getClass().getMethods()) {
  94. if (method.getName().startsWith("set")
  95. && method.getParameterTypes().length == 1
  96. && Modifier.isPublic(method.getModifiers())) {
  97. Class<?> pt = method.getParameterTypes()[0];
  98. try {
  99. String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
  100. Object object = objectFactory.getExtension(pt, property);
  101. if (object != null) {
  102. method.invoke(instance, object);
  103. }
  104. } catch (Exception e) {
  105. logger.error("fail to inject via method " + method.getName()
  106. + " of interface " + type.getName() + ": " + e.getMessage(), e);
  107. }
  108. }
  109. }
  110. }
  111. } catch (Exception e) {
  112. logger.error(e.getMessage(), e);
  113. }
  114. return instance;
  115. }

2.1.1.2、扩展点进行属性注入

如果是扩展点工厂进来了则,不会注入,因为其什么属性都没有

  1. private T injectExtension(T instance) {
  2. try {
  3. if (objectFactory != null) {
  4. for (Method method : instance.getClass().getMethods()) {
  5. if (method.getName().startsWith("set")
  6. && method.getParameterTypes().length == 1
  7. && Modifier.isPublic(method.getModifiers())) {
  8. Class<?> pt = method.getParameterTypes()[0];
  9. try {
  10. String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
  11. Object object = objectFactory.getExtension(pt, property);
  12. if (object != null) {
  13. method.invoke(instance, object);
  14. }
  15. } catch (Exception e) {
  16. logger.error("fail to inject via method " + method.getName()
  17. + " of interface " + type.getName() + ": " + e.getMessage(), e);
  18. }
  19. }
  20. }
  21. }
  22. } catch (Exception e) {
  23. logger.error(e.getMessage(), e);
  24. }
  25. return instance;
  26. }

2.1.2、生成适配扩展点

当没有@Adaotive注解的时候,会帮我们自动生成一个新的扩展点类

  1. private Class<?> getAdaptiveExtensionClass() {
  2. getExtensionClasses();
  3. if (cachedAdaptiveClass != null) {
  4. return cachedAdaptiveClass;
  5. }
  6. //生成适配扩展点
  7. return cachedAdaptiveClass = createAdaptiveExtensionClass();
  8. }
  9. //生成扩展点类,里面会判断是否有@Adaptive注释在方法上,如果没有则报错
  10. private Class<?> createAdaptiveExtensionClass() {
  11. String code = createAdaptiveExtensionClassCode();
  12. ClassLoader classLoader = findClassLoader();
  13. com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  14. return compiler.compile(code, classLoader);
  15. }
  16. private String createAdaptiveExtensionClassCode() {
  17. StringBuilder codeBuilder = new StringBuilder();
  18. Method[] methods = type.getMethods();
  19. boolean hasAdaptiveAnnotation = false;
  20. for (Method m : methods) {
  21. if (m.isAnnotationPresent(Adaptive.class)) {
  22. hasAdaptiveAnnotation = true;
  23. break;
  24. }
  25. }
  26. // no need to generate adaptive class since there's no adaptive method found.
  27. if (!hasAdaptiveAnnotation)
  28. throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
  29. codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
  30. codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
  31. codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");
  32. for (Method method : methods) {
  33. Class<?> rt = method.getReturnType();
  34. Class<?>[] pts = method.getParameterTypes();
  35. Class<?>[] ets = method.getExceptionTypes();
  36. Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
  37. StringBuilder code = new StringBuilder(512);
  38. if (adaptiveAnnotation == null) {
  39. code.append("throw new UnsupportedOperationException(\"method ")
  40. .append(method.toString()).append(" of interface ")
  41. .append(type.getName()).append(" is not adaptive method!\");");
  42. } else {
  43. int urlTypeIndex = -1;
  44. for (int i = 0; i < pts.length; ++i) {
  45. if (pts[i].equals(URL.class)) {
  46. urlTypeIndex = i;
  47. break;
  48. }
  49. }
  50. // found parameter in URL type
  51. if (urlTypeIndex != -1) {
  52. // Null Point check
  53. String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
  54. urlTypeIndex);
  55. code.append(s);
  56. s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
  57. code.append(s);
  58. }
  59. // did not find parameter in URL type
  60. else {
  61. String attribMethod = null;
  62. // find URL getter method
  63. LBL_PTS:
  64. for (int i = 0; i < pts.length; ++i) {
  65. Method[] ms = pts[i].getMethods();
  66. for (Method m : ms) {
  67. String name = m.getName();
  68. if ((name.startsWith("get") || name.length() > 3)
  69. && Modifier.isPublic(m.getModifiers())
  70. && !Modifier.isStatic(m.getModifiers())
  71. && m.getParameterTypes().length == 0
  72. && m.getReturnType() == URL.class) {
  73. urlTypeIndex = i;
  74. attribMethod = name;
  75. break LBL_PTS;
  76. }
  77. }
  78. }
  79. if (attribMethod == null) {
  80. throw new IllegalStateException("fail to create adaptive class for interface " + type.getName()
  81. + ": not found url parameter or url attribute in parameters of method " + method.getName());
  82. }
  83. // Null point check
  84. String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
  85. urlTypeIndex, pts[urlTypeIndex].getName());
  86. code.append(s);
  87. s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
  88. urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
  89. code.append(s);
  90. s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
  91. code.append(s);
  92. }
  93. String[] value = adaptiveAnnotation.value();
  94. // value is not set, use the value generated from class name as the key
  95. if (value.length == 0) {
  96. char[] charArray = type.getSimpleName().toCharArray();
  97. StringBuilder sb = new StringBuilder(128);
  98. for (int i = 0; i < charArray.length; i++) {
  99. if (Character.isUpperCase(charArray[i])) {
  100. if (i != 0) {
  101. sb.append(".");
  102. }
  103. sb.append(Character.toLowerCase(charArray[i]));
  104. } else {
  105. sb.append(charArray[i]);
  106. }
  107. }
  108. value = new String[]{ sb.toString()};
  109. }
  110. boolean hasInvocation = false;
  111. for (int i = 0; i < pts.length; ++i) {
  112. if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
  113. // Null Point check
  114. String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"invocation == null\");", i);
  115. code.append(s);
  116. s = String.format("\nString methodName = arg%d.getMethodName();", i);
  117. code.append(s);
  118. hasInvocation = true;
  119. break;
  120. }
  121. }
  122. String defaultExtName = cachedDefaultName;
  123. String getNameCode = null;
  124. for (int i = value.length - 1; i >= 0; --i) {
  125. if (i == value.length - 1) {
  126. if (null != defaultExtName) {
  127. if (!"protocol".equals(value[i]))
  128. if (hasInvocation)
  129. getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
  130. else
  131. getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
  132. else
  133. getNameCode = String.format("( url.getProtocol() == null ? \"%s\" : url.getProtocol() )", defaultExtName);
  134. } else {
  135. if (!"protocol".equals(value[i]))
  136. if (hasInvocation)
  137. getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
  138. else
  139. getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
  140. else
  141. getNameCode = "url.getProtocol()";
  142. }
  143. } else {
  144. if (!"protocol".equals(value[i]))
  145. if (hasInvocation)
  146. getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
  147. else
  148. getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
  149. else
  150. getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
  151. }
  152. }
  153. code.append("\nString extName = ").append(getNameCode).append(";");
  154. // check extName == null?
  155. String s = String.format("\nif(extName == null) " +
  156. "throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");",
  157. type.getName(), Arrays.toString(value));
  158. code.append(s);
  159. s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
  160. type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
  161. code.append(s);
  162. // return statement
  163. if (!rt.equals(void.class)) {
  164. code.append("\nreturn ");
  165. }
  166. s = String.format("extension.%s(", method.getName());
  167. code.append(s);
  168. for (int i = 0; i < pts.length; i++) {
  169. if (i != 0)
  170. code.append(", ");
  171. code.append("arg").append(i);
  172. }
  173. code.append(");");
  174. }
  175. codeBuilder.append("\npublic ").append(rt.getCanonicalName()).append(" ").append(method.getName()).append("(");
  176. for (int i = 0; i < pts.length; i++) {
  177. if (i > 0) {
  178. codeBuilder.append(", ");
  179. }
  180. codeBuilder.append(pts[i].getCanonicalName());
  181. codeBuilder.append(" ");
  182. codeBuilder.append("arg").append(i);
  183. }
  184. codeBuilder.append(")");
  185. if (ets.length > 0) {
  186. codeBuilder.append(" throws ");
  187. for (int i = 0; i < ets.length; i++) {
  188. if (i > 0) {
  189. codeBuilder.append(", ");
  190. }
  191. codeBuilder.append(ets[i].getCanonicalName());
  192. }
  193. }
  194. codeBuilder.append(" {");
  195. codeBuilder.append(code.toString());
  196. codeBuilder.append("\n}");
  197. }
  198. codeBuilder.append("\n}");
  199. if (logger.isDebugEnabled()) {
  200. logger.debug(codeBuilder.toString());
  201. }
  202. return codeBuilder.toString();
  203. }

author

发表评论

表情:
评论列表 (有 0 条评论,111人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Dubbo SPI

    前言 前面已经讲过[JDK SPI][], dubbo SPI主要基于JDK SPI机制,进行了增强,实现可扩展 为什么不直接用JDK的SPI呢,主要有哪些改变