Dubbo SPI机制ExtensionLoader浅析

深碍√TFBOYSˉ_ 2022-10-22 04:21 82阅读 0赞

1.getExtensionLoader

返回SPI接口对应的ExtensionLoader

  1. // 根据类型查找对应的扩展加载器,如果没有,则创建一个并且加入EXTENSION_LOADERS
  2. public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  3. if (type == null) {
  4. throw new IllegalArgumentException("Extension type == null");
  5. }
  6. if (!type.isInterface()) {
  7. throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
  8. }
  9. if (!withExtensionAnnotation(type)) {
  10. throw new IllegalArgumentException("Extension type (" + type +
  11. ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
  12. }
  13. // private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
  14. ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  15. if (loader == null) {
  16. // private final Class<?> type;
  17. EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
  18. loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  19. }
  20. return loader;
  21. }

2.getExtension

根据扩展点名称获取对应的实现类实例

  1. public T getExtension(String name) {
  2. if (StringUtils.isEmpty(name)) {
  3. throw new IllegalArgumentException("Extension name == null");
  4. }
  5. if ("true".equals(name)) {
  6. return getDefaultExtension();
  7. }
  8. // private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
  9. // 根据扩展名查找对应的Holder,如果没有则创建一个并放入cachedInstances
  10. // 如果有的话直接返回缓存的实例
  11. final Holder<Object> holder = getOrCreateHolder(name);
  12. Object instance = holder.get();
  13. if (instance == null) {
  14. synchronized (holder) {
  15. instance = holder.get();
  16. if (instance == null) {
  17. // 创建扩展点实现
  18. instance = createExtension(name);
  19. holder.set(instance);
  20. }
  21. }
  22. }
  23. return (T) instance;
  24. }
  25. private T createExtension(String name) {
  26. // 如果cachedClasses为空,使用三种LoadingStrategy从三个目录中获取name对应的CLass
  27. Class<?> clazz = getExtensionClasses().get(name);
  28. if (clazz == null) {
  29. throw findException(name);
  30. }
  31. try {
  32. T instance = (T) EXTENSION_INSTANCES.get(clazz);
  33. if (instance == null) {
  34. // 如果缓存中没有,则通过newInstance方法创建实例并放入EXTENSION_INSTANCES中
  35. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
  36. instance = (T) EXTENSION_INSTANCES.get(clazz);
  37. }
  38. injectExtension(instance);
  39. Set<Class<?>> wrapperClasses = cachedWrapperClasses;
  40. if (CollectionUtils.isNotEmpty(wrapperClasses)) {
  41. for (Class<?> wrapperClass : wrapperClasses) {
  42. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  43. }
  44. }
  45. initExtension(instance);
  46. return instance;
  47. } catch (Throwable t) {
  48. throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
  49. type + ") couldn't be instantiated: " + t.getMessage(), t);
  50. }
  51. }

发表评论

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

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

相关阅读

    相关 jdk和dubboSPI机制

    [jdk和dubbo的SPI机制][jdk_dubbo_SPI] 前言:开闭原则一直是软件开发领域中所追求的,开闭原则中的"开"是指对于组件功能的扩展是开放的,是允许对其