一、深入理解SPI机制及源码分析

  怀着激动,兴奋,忐忑的心情写下第一篇博客,希望以后能在CSDN和大家一起开心的玩耍!!!
我确实不太会擅长写博客,但还是想把一些技术分享给大家,一起进步。
也希望大家多多交流,指正。

下面我们话不多说,直接进入正题。深入SPI机制

一、SPI机制理解

  SPI 全称为 Service Provider Interface 是一种服务发现机制。
它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。

实现步骤:
1、在ClassPath路径下的META-INF/services文件夹下创建文件
2、文件名为接口服务的全限定名,文件内容是多个实现类
3、API加载实现类。

下面让我小试牛刀一把…

二、Java SPI 案例

1、首先编写一个接口服务 SPIService ,就一个execute方法

public interface SPIService {
    void execute();
}

2、创建两个接口实现类 SPIServiceImpl1 和 SPIServiceImpl2,实现execute方法

public class SPIServiceImpl1 implements SPIService {
    @Override
    public void execute() {
        System.out.println( this.getClass().getSimpleName() + "....execute..........");
    }
}
public class SPIServiceImpl2 implements SPIService{
    @Override
    public void execute() {
        System.out.println( this.getClass().getSimpleName() + "....execute..........");
    }
}

3、在META-INF/services 下创建文件,文件名为com.xyy.spi.java.SPIService 即接口全限定名,文件内容为两个实现类的全限定名。

com.xyy.spi.java.SPIServiceImpl1
com.xyy.spi.java.SPIServiceImpl2

如图:
在这里插入图片描述

4、准备就绪,我们来编写一个测试类,看看效果

public class SPIMainClass {

    @Test
    public void test() {
       
        //方式一:sun.misc.Service 加载
        Iterator<SPIService> providers = Service.providers(SPIService.class);
        while (providers.hasNext()) {
            SPIService servcie = providers.next();
            servcie.execute();
        }
        System.out.println("**************************************************");
        //方式二:java.util.ServiceLoader 加载
        ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
        Iterator<SPIService> iterator = load.iterator();
        while (iterator.hasNext()) {
            SPIService servcie = iterator.next();
            servcie.execute();
        }

    }

}

运行结果:
在这里插入图片描述

这里我们输出了实现类1和2 的execute方法。我们采用了两种加载的方式,sun.misc.Service 加载和
java.util.ServiceLoader 加载,大同小异。下面我们去看看源码他们是如何实现的。

三、Java SPI 源码分析

1、sun.misc.Service 加载源码

以这个代码为入口debug调试下,看下源码

 Iterator<SPIService> providers = Service.providers(SPIService.class);

跟踪代码

    public static <S> Iterator<S> providers(Class<S> var0) throws ServiceConfigurationError {
        //获得当前线程的ClassLoader
        ClassLoader var1 = Thread.currentThread().getContextClassLoader();
        return providers(var0, var1);
    }

实例化Service.LazyIterator

public static <S> Iterator<S> providers(Class<S> var0, ClassLoader var1) throws ServiceConfigurationError {
        //实例化Service.LazyIterator 
        // var0 是com.xyy.spi.java.SPIService 
        // var1 是线程的ClassLoader
        return new Service.LazyIterator(var0, var1);
 }

属性赋值

private LazyIterator(Class<S> var1, ClassLoader var2) {
       this.configs = null;
       this.pending = null;
       this.returned = new TreeSet();
       this.nextName = null;
       //service 是com.xyy.spi.java.SPIService
       this.service = var1;
       this.loader = var2;
   }

这里LazyIterator是Service的内部类,实现Iterator接口,看名字就是个懒加载的迭代器…

private static class LazyIterator<S> implements Iterator<S> {
        //保存我们的接口
        Class<S> service;
        //当前线程的ClassLoader
        ClassLoader loader;
        //我们的配置资源
        Enumeration<URL> configs;
        //配置内容信息,也就是实现类1和2
        Iterator<String> pending;
        Set<String> returned;
        String nextName;
        ...
}

下面到了看看我们迭代的时候啦

  while (providers.hasNext()) {
       SPIService servcie = providers.next();
       servcie.execute();
   }

跟踪这个 providers.hasNext()

public boolean hasNext() throws ServiceConfigurationError {
    //判断nextName 是否为空,不为空就返回true。后面直接next获取
    if(this.nextName != null) {
        return true;
    } else {
        if(this.configs == null) {
            try {
                //var1 是 META-INF/services/com.xyy.spi.java.SPIService
                String var1 = "META-INF/services/" + this.service.getName();
                if(this.loader == null) {
                    this.configs = ClassLoader.getSystemResources(var1);
                } else {
                    this.configs = this.loader.getResources(var1);
                }
            } catch (IOException var2) {
                Service.fail(this.service, ": " + var2);
            }
        }

        while(this.pending == null || !this.pending.hasNext()) {
            if(!this.configs.hasMoreElements()) {
                return false;
            }
			//解析配置
            this.pending = Service.parse(this.service, (URL)this.configs.nextElement(), this.returned);
        }
		//设置nextName
        this.nextName = (String)this.pending.next();
        return true;
    }
}

下面我们看看parse解析方法

private static Iterator<String> parse(Class<?> var0, URL var1, Set<String> var2) throws ServiceConfigurationError {
   InputStream var3 = null;
    BufferedReader var4 = null;
    ArrayList var5 = new ArrayList();

    try {
        var3 = var1.openStream();
        var4 = new BufferedReader(new InputStreamReader(var3, "utf-8"));
        int var6 = 1;

        while(true) {
            //解析行
            if((var6 = parseLine(var0, var1, var4, var6, var5, var2)) >= 0) {
                continue;
            }
        }
    } catch (IOException var15) {
        fail(var0, ": " + var15);
    } finally {
        try {
            if(var4 != null) {
                var4.close();
            }

            if(var3 != null) {
                var3.close();
            }
        } catch (IOException var14) {
            fail(var0, ": " + var14);
        }

    }

    return var5.iterator();
}

hasNext主要是解析了我们的配置文件,赋值给迭代器。我们现在到了next方法

 SPIService servcie = providers.next();

next方法

public S next() throws ServiceConfigurationError {
  //先去判断hasNext
  if(!this.hasNext()) {
         throw new NoSuchElementException();
     } else {
         //有的话,直接获取nextName
         String var1 = this.nextName;
         this.nextName = null;
         Class var2 = null;

         try {
          	 //类加载var1 使我们的实现类1或2的权限定名
             var2 = Class.forName(var1, false, this.loader);
         } catch (ClassNotFoundException var5) {
             Service.fail(this.service, "Provider " + var1 + " not found");
         }

         if(!this.service.isAssignableFrom(var2)) {
             Service.fail(this.service, "Provider " + var1 + " not a subtype");
         }

         try {
             //反射创建实例,转化成接口
             return this.service.cast(var2.newInstance());
         } catch (Throwable var4) {
             Service.fail(this.service, "Provider " + var1 + " could not be instantiated", var4);
             return null;
         }
     }
 }

现在我们就获得了配置的扩展类对象实例啦。
看了源码,大致画了个分析流程图,总体源码还是不难,大家只要debug跟踪下就理解啦。

在这里插入图片描述

  总结:
    1、创建Service.LazyIterator,设置service等属性
    2、hasNext加载META-INF/services下接口文件内容,设置LazyIterator的nextName属性等
    3、next方法获得nextName,Class.forName加载类,反射实例化

2、java.util.ServiceLoader 加载源码

看完了上面的加载方式的源码,我们再看看java.util.ServiceLoader 加载源码,就更简单啦

ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);

debug下

public static <S> ServiceLoader<S> load(Class<S> service) {
    //同样的当前线程的ClassLoader
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    //调用load
    return ServiceLoader.load(service, cl);
}

load方法

  public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }

实例化ServiceLoader

 private ServiceLoader(Class<S> svc, ClassLoader cl) {
      //我们的接口服务 com.xyy.spi.java.SPIService
      service = Objects.requireNonNull(svc, "Service interface cannot be null");
      loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
      acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
      //重新加载
      reload();
  }

reload方法

 public void reload() {  
     //清除缓存
     providers.clear();
     //创建LazyIterator
     lookupIterator = new LazyIterator(service, loader);
 }

我们看看ServiceLoader 类,实现Iterable

public final class ServiceLoader<S>
    implements Iterable<S>
{
    //加载配置目录
    private static final String PREFIX = "META-INF/services/";

    // 我们的接口
    private final Class<S> service;

    private final ClassLoader loader;

    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;

    // 类名和实例的映射,缓存
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // The current lazy-lookup iterator
    private LazyIterator lookupIterator;
    ...
 }

上面完成初始化,下面看下

 Iterator<SPIService> iterator = load.iterator();

iterator方法

public Iterator<S> iterator() {
        //新建一个Iterator 返回
        return new Iterator<S>() {
    //将缓存结果,设置给knownProviders
    Iterator<Map.Entry<String,S>> knownProviders
        = providers.entrySet().iterator();
    //这个判断是否hasNext
    public boolean hasNext() {
        //缓存有
        if (knownProviders.hasNext())
            return true;
        //缓存没有,调用 LazyIterator 的hasNext
        return lookupIterator.hasNext();
    }
    // 获取
    public S next() {
        //缓存有,从缓存中获取对象实例
        if (knownProviders.hasNext())
            return knownProviders.next().getValue();
        // 缓存没有,调用 LazyIterator 的next
        return lookupIterator.next();
    }

    public void remove() {
        throw new UnsupportedOperationException();
    }

 };
}

后面测试代码的迭代获取,会调用上面的Iterator的相关方法

 while (iterator.hasNext()) {
      SPIService servcie = iterator.next();
      servcie.execute();
  }

LazyIterator 的hasNext方法

public boolean hasNext() {
     if (acc == null) {
         //调用hasNextService
         return hasNextService();
     } else {
         PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
             public Boolean run() { return hasNextService(); }
         };
         return AccessController.doPrivileged(action, acc);
     }
 }

hasNextService方法,这个代码可真是太熟悉啦,上面第一个加载方式的源码分析过了类似。

private boolean hasNextService() {
   if (nextName != null) {
       return true;
   }
   if (configs == null) {
       try {
           String fullName = PREFIX + service.getName();
           if (loader == null)
               configs = ClassLoader.getSystemResources(fullName);
           else
               configs = loader.getResources(fullName);
       } catch (IOException x) {
           fail(service, "Error locating configuration files", x);
       }
   }
   while ((pending == null) || !pending.hasNext()) {
       if (!configs.hasMoreElements()) {
           return false;
       }
       pending = parse(service, configs.nextElement());
   }
   nextName = pending.next();
   return true;
}

LazyIterator 的next方法

public S next() {
    if (acc == null) {
        //调用nextService
        return nextService();
    } else {
        PrivilegedAction<S> action = new PrivilegedAction<S>() {
            public S run() { return nextService(); }
        };
        return AccessController.doPrivileged(action, acc);
    }
}
private S nextService() {
   if (!hasNextService())
        throw new NoSuchElementException();
    String cn = nextName;
    nextName = null;
    Class<?> c = null;
    try {
        c = Class.forName(cn, false, loader);
    } catch (ClassNotFoundException x) {
        fail(service,
             "Provider " + cn + " not found");
    }
    if (!service.isAssignableFrom(c)) {
        fail(service,
             "Provider " + cn  + " not a subtype");
    }
    try {
        //反射实例化
        S p = service.cast(c.newInstance());
        //放入缓存
        providers.put(cn, p);
        return p;
    } catch (Throwable x) {
        fail(service,
             "Provider " + cn + " could not be instantiated",
             x);
    }
    throw new Error();          // This cannot happen
}

到此源码就分析完了,其实和第一种真的没啥大区别,只是多了一个缓存。
源码大致的流程图
在这里插入图片描述

总结:
  1、初始化 ServiceLoader,设置lookupIterator属性为LazyIterator
  2、hasNext先从缓存的providers中获取,为空,则去加载META-INF/services下接口文件内容,设置LazyIterator的nextName属性等
  3、next方法获得nextName,Class.forName加载类,反射实例化,放入providers

四、Java SPI 应用

1、JDBC驱动

1、我们自己创建一个驱动类,MyDriver,方便起见,我们需要extends com.mysql.cj.jdbc.NonRegisteringDriver implements java.sql.Driver

    public class MyDriver extends com.mysql.cj.jdbc.NonRegisteringDriver implements java.sql.Driver{
      public MyDriver() throws SQLException {
      }
  
      static {
          try {
              System.out.println("register MyDriver...");
              //注册我们的驱动
              DriverManager.registerDriver(new MyDriver());
          } catch (SQLException var1) {
              throw new RuntimeException("Can't register MyDriver!");
          }
      }
  
      @Override
      public Connection connect(String url, Properties info) throws SQLException {
          System.out.println("创建连接..."+ url);
          System.out.println("jdbc配置信息..." + info);
          Connection connect = super.connect(url, info);
          System.out.println("数据库连接创建完成..."+ connect.toString());
          return connect;
      }
    }


2、在META-INF/services下创建java.sql.Driver文件,内容为:com.xyy.spi.jdbc.MyDriver

com.xyy.spi.jdbc.MyDriver

3、测试类

  @Test
  public  void test() throws Exception {

      String url = "jdbc:mysql://127.0.0.1:3306/db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true&allowMultiQueries=true&useSSL=false";
      String user = "root";
      String password = "root";

      /**
       * 不需要这个啦
       */
      //Class.forName("com.xyy.spi.jdbc.MyDriver");
      Connection connection = DriverManager.getConnection(url, user, password);
      PreparedStatement preparedStatement = connection.prepareStatement("SELECT id FROM table");

      ResultSet resultSet = preparedStatement.executeQuery();
      while (resultSet.next()){
          Long id = resultSet.getLong(1);
          System.out.println("id=="+ id);
      }

      preparedStatement.close();
      connection.close();


  }

运行结果:
在这里插入图片描述
看着结果就已经回调了我们的类。那么是如何加载到MyDriver?细节就不展开了,看着图debug跟踪下代码,就清楚啦

总结:
   1、DriverManager类加载时,静态代码块调用loadInitialDrivers(),SPI机制加载META-INF/services/java.sql.Driver内的实现类
   2、加载MyDriver的静态方法,注册MyDriver
   3、DriverManager的getConnection方法,会遍历注册驱动,调用驱动类的connnect方法

源码分析流程图:
在这里插入图片描述

2、Dubbo应用

dubbo的SPI机制:
1、接口有@SPI注解,指定默认实现
2、加载三个路径: META-INF/services/、META-INF/dubbo/、META-INF/services/internal

示例1 、扩展dubbo的Protocol接口服务

1、创建类MyProtocol,实现Protocol

   
   public class MyProtocol implements Protocol {

   /**
    * 我们重写了默认端口
    * @return
    */
   @Override
   public int getDefaultPort() {
       return 8888;
   }

   @Override
   public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
       return null;
   }

   @Override
   public <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException {
       return null;
   }

   @Override
   public void destroy() {

   }
}

2、在META-INF/dubbo/下创建文件com.alibaba.dubbo.rpc.Protocol,内容

MyProtocol=com.xyy.spi.dubbo.MyProtocol

3、测试代码

    @Test
    public void testMyProtocol(){

        ExtensionLoader<Protocol> extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class);
        Protocol myProtocol = extensionLoader.getExtension("MyProtocol");
        System.out.println(myProtocol.getDefaultPort());
    }

运行结果:
在这里插入图片描述

示例2、我们自己定义接口服务

1、创建接口DubboService,写上 @SPI(“dubboService1”)注解,默认是dubboService1

    @SPI("dubboService1")
    public interface DubboService {
        public void sayHello();
    }

2、创建DubboService接口的两个实现类

public class DubboServiceImp1 implements DubboService {
    @Override
    public void sayHello() {
        System.out.println("DubboServiceImp1...hello");
    }
}
public class DubboServiceImp2 implements DubboService {
    @Override
    public void sayHello() {
        System.out.println("DubboServiceImp2...hello");
    }
}

3、在META-INF/dubbo/下创建文件com.xyy.spi.dubbo.DubboService,内容

dubboService1=com.xyy.spi.dubbo.DubboServiceImp1
dubboService2=com.xyy.spi.dubbo.DubboServiceImp2

4、测试代码

    @Test
    public void testDubboService(){
        ExtensionLoader<DubboService> extensionLoader1 = ExtensionLoader.getExtensionLoader(DubboService.class);
        DubboService dubboService = extensionLoader1.getExtension("dubboService1");
        dubboService.sayHello();
    }

运行结果:
在这里插入图片描述
源码分析
入口:


ExtensionLoader.getExtensionLoader(DubboService.class);

看下 ExtensionLoader.getExtensionLoader方法:

    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null)
            throw new IllegalArgumentException("Extension type == null");
		//必须是接口	
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
		//必须有@SPI注解
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        //从缓存中获取接口对应的ExtensionLoader,EXTENSION_LOADERS 是ConcurrentMap<Class<?>, ExtensionLoader<?>>
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
		    //创建ExtensionLoader,放入缓存
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

这个ExtensionLoader.withExtensionAnnotation方法,查看是否有SPI注解:

    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }

创建 new ExtensionLoader(type)方法:

   private ExtensionLoader(Class<?> type) {
       //接口服务的class
       this.type = type;
   	//如果类型是ExtensionFactory.class 则设为null,否则就是再次使用SPI机制获得ExtensionFactory
       objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
   }

下面我们看下获得具体扩展的方法 这个getExtension(String name):

   public T getExtension(String name) {
       //为空,则报异常
       if (name == null || name.length() == 0)
           throw new IllegalArgumentException("Extension name == null");
   	//如是字符串"true",则获取默认的扩展实例。	
       if ("true".equals(name)) {
           return getDefaultExtension();
       }
       Holder<Object> holder = cachedInstances.get(name);
       if (holder == null) {
           cachedInstances.putIfAbsent(name, new Holder<Object>());
           holder = cachedInstances.get(name);
       }
       Object instance = holder.get();
       if (instance == null) {
           synchronized (holder) {
               instance = holder.get();
               if (instance == null) {
   			    //创建指定的扩展实例
                   instance = createExtension(name);
                   holder.set(instance);
               }
           }
       }
       return (T) instance;
   }

创建指定的扩展,createExtension方法:

   private T createExtension(String name) {
       //从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
       //获得指定扩展的class对象
       Class<?> clazz = getExtensionClasses().get(name);
       if (clazz == null) {
           throw findException(name);
       }
       try {
           T instance = (T) EXTENSION_INSTANCES.get(clazz);
           if (instance == null) {
   		    //实例化,放入缓存
               EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
               instance = (T) EXTENSION_INSTANCES.get(clazz);
           }
   		//依赖注入和cachedWrapperClasses
           injectExtension(instance);
           Set<Class<?>> wrapperClasses = cachedWrapperClasses;
           if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
               for (Class<?> wrapperClass : wrapperClasses) {
                   instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
               }
           }
           return instance;
       } catch (Throwable t) {
           throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                   type + ")  could not be instantiated: " + t.getMessage(), t);
       }
   }

获得所有的扩展getExtensionClasses()方法:

  private Map<String, Class<?>> getExtensionClasses() {
      //缓存中获取映射关系表
      Map<String, Class<?>> classes = cachedClasses.get();
      if (classes == null) {
          synchronized (cachedClasses) {
              classes = cachedClasses.get();
              if (classes == null) {
  			    //加载映射关系表
                  classes = loadExtensionClasses();
                  cachedClasses.set(classes);
              }
          }
      }
      return classes;
  }

loadExtensionClasses()方法:

  private Map<String, Class<?>> loadExtensionClasses() {
      //获得注解指定的默认值
      final SPI defaultAnnotation = type.getAnnotation(SPI.class);
      if (defaultAnnotation != null) {
          String value = defaultAnnotation.value();
          if ((value = value.trim()).length() > 0) {
              String[] names = NAME_SEPARATOR.split(value);
              if (names.length > 1) {
                  throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                          + ": " + Arrays.toString(names));
              }
  			// 获取@SPI注解中的值,并缓存起来
              if (names.length == 1) cachedDefaultName = names[0];
          }
      }

      Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
  	//加载指定文件夹下的配置文件,META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
      loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
      loadDirectory(extensionClasses, DUBBO_DIRECTORY);
      loadDirectory(extensionClasses, SERVICES_DIRECTORY);
      return extensionClasses;
  }

加载目录loadDirectory方法:

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
	    //  fileName 是 META-INF/dubbo/com.xyy.spi.dubbo.DubboService
        String fileName = dir + type.getName();
        try {
            Enumeration<java.net.URL> 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 resourceURL = urls.nextElement();
					//加载文件,一个resourceURL就是一个文件
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

loadResource方法加载资源:

    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                String line;
                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) {
							    //加载类
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }

loadClass方法加载class:


    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        // clazz 必须是type类型的
		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.");
        }
		//判断clazz是否为标注了@Adaptive注解
        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());
            }
        } 
		//判断是否是Wrapper类型
		else if (isWrapperClass(clazz)) {
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
		    //clazz是一个普通的拓展类
			//获得默认构造
            clazz.getConstructor();
            if (name == null || name.length() == 0) {
			    //name 配置为空,去类上找@Extension注解
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }
            String[] names = NAME_SEPARATOR.split(name);
            if (names != null && names.length > 0) {
			    //判断clazz是否为标注了@Activate注解
                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) {
					    // 存储名称到class的映射关系,这样就解析好了一行
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }

查看处理@Extension注解,findAnnotationName方法:

    private String findAnnotationName(Class<?> clazz) {
        com.alibaba.dubbo.common.Extension extension = clazz.getAnnotation(com.alibaba.dubbo.common.Extension.class);
		//没注解,再去判断
        if (extension == null) {
            String name = clazz.getSimpleName();
			//扩展类名是否以接口的名称结尾,包含的话,就截取扩展类前面的部分,不包含的话就直接扩展类名
            if (name.endsWith(type.getSimpleName())) {
                name = name.substring(0, name.length() - type.getSimpleName().length());
            }
			//转成小写
            return name.toLowerCase();
        }
		//有注解,返回注解value
        return extension.value();
    }

源码分析流程图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kAkVvXp-1646269344916)(831052A92835495B98589C93511A2646)]

示例3、dubbo的Adaptive及Wrapper详解

1、创建接口

@SPI("dubbo")
public interface AdaptiveExtService {
    //@Adaptive
    //@Adaptive({"param"})
    String run(String msg, URL url);
}

2、创建多个实现类

public class DubboAdaptiveExt implements AdaptiveExtService {
    @Override
    public String run(String msg, URL url) {
        return "dubbo";
    }
}

public class SpringCloudAdaptiveExt implements AdaptiveExtService {
    @Override
    public String run(String msg, URL url) {
        return "spring cloud";
    }
}

//@Adaptive
public class ThriftAdaptiveExt implements AdaptiveExtService {
    @Override
    public String run(String msg, URL url) {
        return "thrift";
    }
}

3、在META-INF/dubbo下创建文件,文件名称:com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt,内容为

dubbo=com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt
cloud=com.xyy.spi.dubbo.adaptive.SpringCloudAdaptiveExt
thrift=com.xyy.spi.dubbo.adaptive.ThriftAdaptiveExt

4、编写测试类观察

(1)、测试1

    /**
     * SPI上有注解,@SPI("dubbo")
     * url无参数
     * 没有扩展类上添加@Adaptive注解
     * 接口方法不加@Adaptive注解
     * 
     */
    @Test
    public void test1(){
        ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
        AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("http://localhost/xxx");
        System.out.println(adaptiveExtension.run("hello", url));
    }

运行结果:
在这里插入图片描述
结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,则接口必须有@Adaptive注解的方法。
(2)、测试2

    /**
     * SPI上有注解,@SPI("dubbo")
     * url无参数
     * 没有扩展类上添加@Adaptive注解
     * 方法上有@Adaptive注解,无参数
     */
    @Test
    public void test2(){
        ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
        AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("http://localhost/xxx");
        System.out.println(adaptiveExtension.run("hello", url));
    }

运行结果:
在这里插入图片描述

结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,会得到@SPI(“dubbo”)指定的默认的扩展类。

(3)、测试3

    /**
     * SPI上有注解@SPI("dubbo")
     * URL中也有具体的值
     * 没有扩展类上添加@Adaptive注解
     * 注意这里对方法标注有@Adaptive注解,
     * 但是该注解没有值
     */
    @Test
    public void test3(){
        ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
        AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("http://localhost/xxx?adaptive.ext.service=cloud");
        System.out.println(adaptiveExtension.run("hello", url));
    }

运行结果:
在这里插入图片描述
结论:使用getAdaptiveExtension()方法,没有@Adaptive注解的扩展类,有url参数,该参数通过AdaptiveExtService转小写生成(adaptive.ext.service=cloud),则会获得cloud对应的实例。
(4)、测试4

    /**
     * SPI上有注解,@SPI("dubbo")
     * URL中也有具体的值
     * ThriftAdaptiveExt实现类上面添加@Adaptive注解
     */
    @Test
    public void test4(){
        ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
        AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("http://localhost/xxx?adaptive.ext.service=cloud");
        System.out.println(adaptiveExtension.run("d", url));
    }

运行结果:
在这里插入图片描述
结论:使用getAdaptiveExtension()方法,实现类上面添加@Adaptive注解的优先级高与url参数指定的

(5)、测试5

    /**
     * SPI上有注解,@SPI("dubbo")
     * URL中也有具体的值,接口方法中加上注解@Adaptive({"param"}),
     * 各个实现类上面没有@Adaptive注解
     */
    @Test
    public void test5(){
        ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
        AdaptiveExtService adaptiveExtension = loader.getAdaptiveExtension();
        URL url = URL.valueOf("http://localhost/xxx?param=cloud");
        System.out.println(adaptiveExtension.run("d", url));
    }

运行结果:

在这里插入图片描述
结论:使用getAdaptiveExtension()方法,方法上有注解@Adpative({“param”}),则URL中应当配上该参数param=cloud,创建cloud对应的实例

通过上面测试发现:

可以得出优先级: @Adaptive标注的类 > URL参数 > @SPI注解中的值

源码分析:
getAdaptiveExtension()方法为入口:

public T getAdaptiveExtension() {
    //先从缓存中获取
	Object instance = cachedAdaptiveInstance.get();
	if (instance == null) {
		if (createAdaptiveInstanceError == null) {
			synchronized (cachedAdaptiveInstance) {
				instance = cachedAdaptiveInstance.get();
				if (instance == null) {
					try {
					    //创建自适应的扩展类
						instance = createAdaptiveExtension();
						//放入缓存
						cachedAdaptiveInstance.set(instance);
					} catch (Throwable t) {
						createAdaptiveInstanceError = t;
						throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
					}
				}
			}
		} else {
			throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
		}
	}

	return (T) instance;
}

创建自适应的扩展类实例 createAdaptiveExtension()方法:

private T createAdaptiveExtension() {
	try {
	    //getAdaptiveExtensionClass()获得自适应的扩展class
		//反射获得扩展类的实例
		//依赖注入
		return injectExtension((T) getAdaptiveExtensionClass().newInstance());
	} catch (Exception e) {
		throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
	}
}

获得自适应的扩展类class方法 getAdaptiveExtensionClass:

private Class<?> getAdaptiveExtensionClass() {
    //获得所有扩展类,加载配置文件,之前看过,这里就不展开了
	getExtensionClasses();
	//如果有标注了@Adaptive注解实现类,那么cachedAdaptiveClass不为空,直接返回,表明@Adaptive注解标明的扩展类优先级最高
	if (cachedAdaptiveClass != null) {
		return cachedAdaptiveClass;
	}
	//创建自适应的扩展类
	return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

创建自适应的扩展类class方法 createAdaptiveExtensionClass:

private Class<?> createAdaptiveExtensionClass() {
    //创建扩展类class字符串
	String code = createAdaptiveExtensionClassCode();
	ClassLoader classLoader = findClassLoader();
	//获得自适应的扩展编译器
	com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
	//编译我们生成的code字符串
	return compiler.compile(code, classLoader);
}

生成扩展class内容字符串,createAdaptiveExtensionClassCode 方法:

private String createAdaptiveExtensionClassCode() {
	StringBuilder codeBuilder = new StringBuilder();
	//获取接口的方法
	Method[] methods = type.getMethods();
	boolean hasAdaptiveAnnotation = false;
	for (Method m : methods) {
	    //方法是否有@Adaptive注解
		if (m.isAnnotationPresent(Adaptive.class)) {
			hasAdaptiveAnnotation = true;
			break;
		}
	}
	//方法没有注解,抛异常,至少有一个方法有注解
	// no need to generate adaptive class since there's no adaptive method found.
	if (!hasAdaptiveAnnotation)
		throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
    //生成包信息 package com.xyy.spi.dubbo.adaptive;r
	codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
	//生成import信息 import com.alibaba.dubbo.common.extension.ExtensionLoader;
	codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
	生成类名 public class AdaptiveExtService$Adaptive implements com.xyy.spi.dubbo.adaptive.AdaptiveExtService {
	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);
	    //没有 @Adaptive注解的方法 抛异常UnsupportedOperationException
		if (adaptiveAnnotation == null) {
			code.append("throw new UnsupportedOperationException(\"method ")
					.append(method.toString()).append(" of interface ")
					.append(type.getName()).append(" is not adaptive method!\");");
		} else {
		    //找到URL类型参数
			int urlTypeIndex = -1;
			for (int i = 0; i < pts.length; ++i) {
				if (pts[i].equals(URL.class)) {
					urlTypeIndex = i;
					break;
				}
			}
			//存在url参数
			// found parameter in URL type
			if (urlTypeIndex != -1) {
			    //如果参数是空  if (arg1 == null) throw new IllegalArgumentException("url == null");
				// Null Point check 
				String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
						urlTypeIndex);
				code.append(s);
                //获取url  com.alibaba.dubbo.common.URL url = arg1;
				s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
				code.append(s);
			}
			//没有URL参数
			// did not find parameter in URL type
			else {
				String attribMethod = null;

				// find URL getter method
				LBL_PTS:
				for (int i = 0; i < pts.length; ++i) {
					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
				String 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);

				s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
				code.append(s);
			}
            //获取注解值,  我们配置的@Adaptive({"param"})
			String[] value = adaptiveAnnotation.value();
			//没有值的情况,我们获得接口名称,遇到大写字母,则追加.,大写转小写,如 adaptive.ext.service
			// value is not set, use the value generated from class name as the key
			if (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()};
			}
			//hasInvocation 暂不分析,TODO
			boolean hasInvocation = false;
			for (int i = 0; i < pts.length; ++i) {
				if (pts[i].getName().equals("com.alibaba.dubbo.rpc.Invocation")) {
					// Null Point check
					String 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;
				}
			}
			//defaultExtName是dubbo  @SPI("dubbo")指定的
			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);
							else
								getNameCode = String.format("url.getParameter(\"%s\", \"%s\")", value[i], defaultExtName);
						else
							getNameCode = 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);
							else
								getNameCode = String.format("url.getParameter(\"%s\")", value[i]);
						else
							getNameCode = "url.getProtocol()";
					}
				} else {
					if (!"protocol".equals(value[i]))
						if (hasInvocation)
							getNameCode = String.format("url.getMethodParameter(methodName, \"%s\", \"%s\")", value[i], defaultExtName);
						else
							getNameCode = String.format("url.getParameter(\"%s\", %s)", value[i], getNameCode);
					else
						getNameCode = String.format("url.getProtocol() == null ? (%s) : url.getProtocol()", getNameCode);
				}
			}
			// 获取扩展名  String extName = url.getParameter("param", "dubbo");
			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);
            //生成 com.xyy.spi.dubbo.adaptive.AdaptiveExtService extension = (com.xyy.spi.dubbo.adaptive.AdaptiveExtService)ExtensionLoader.getExtensionLoader(com.xyy.spi.dubbo.adaptive.AdaptiveExtService.class).getExtension(extName);
			s = String.format("\n%s extension = (%<s)%s.getExtensionLoader(%s.class).getExtension(extName);",
					type.getName(), ExtensionLoader.class.getSimpleName(), type.getName());
			code.append(s);

            //生成返回 return extension.run(arg0, arg1);
			// return statement
			if (!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(");");
		}
        // 生成方法名,参数,返回值,异常  public java.lang.String run(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
		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();
}

最终生成返回结果:

package com.xyy.spi.dubbo;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class AdaptiveExtService$Adaptive implements com.xyy.spi.dubbo.adaptive.AdaptiveExtService {
    public java.lang.String run(java.lang.String arg0, com.alibaba.dubbo.common.URL arg1) {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = url.getParameter("param", "dubbo");
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.xyy.spi.dubbo.adaptive.AdaptiveExtService) name from url(" + url.toString() + ") use keys([param])");
        com.xyy.spi.dubbo.adaptive.AdaptiveExtService extension = (com.xyy.spi.dubbo.adaptive.AdaptiveExtService) ExtensionLoader.getExtensionLoader(com.xyy.spi.dubbo.adaptive.AdaptiveExtService.class).getExtension(extName);
        return extension.run(arg0, arg1);
    }
}

源码流程图:

在这里插入图片描述

依赖注入:

//依赖注入
private T injectExtension(T instance) {
    try {
	   // objectFactory 实在实例化ExtensionLoader时以spi形式初始化的
        if (objectFactory != null) {
		    //遍历DubboAdaptiveExt实例的所有方法,寻找set开头且参数为1个,且方法权限为public的方法
            for (Method method : instance.getClass().getMethods()) {
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    /**
                     * Check {@link DisableInject} to see if we need auto injection for this property
                     */
					//@DisableInject标记的方法注解不注入
                    if (method.getAnnotation(DisableInject.class) != null) {
                        continue;
                    }
                    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;
}

初始化objectFactory,spi加载ExtensionFactory

//会初始化objectFactory,spi加载ExtensionFactory
 private ExtensionLoader(Class<?> type) {
    this.type = type;
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

SPI加载com.alibaba.dubbo.common.extension.ExtensionFactory文件内容:

adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory

AdaptiveExtensionFactory 存在@Adaptive 注解,默认会优先选中

//@Adaptive 存在,默认会优先选中
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    //维护SpringExtensionFactory和SpiExtensionFactory
    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
	    
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

遍历factory中所有的ExtensionFactory,先从SpiExtensionFactory中获取,获取不到在去Spring容器中获取

@Override
public <T> T getExtension(Class<T> type, String name) {
   for (ExtensionFactory factory : factories) {
       T extension = factory.getExtension(type, name);
       if (extension != null) {
           return extension;
       }
   }
   return null;
}

SpiExtensionFactory的getExtension方法

//SpiExtensionFactory中获取	
public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
			    //获取自适应的
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

}

SpringExtensionFactory的getExtension方法

//Spring容器中获取
public class SpringExtensionFactory implements ExtensionFactory {
    private static final Logger logger = LoggerFactory.getLogger(SpringExtensionFactory.class);

    private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();

    public static void addApplicationContext(ApplicationContext context) {
        contexts.add(context);
    }

    public static void removeApplicationContext(ApplicationContext context) {
        contexts.remove(context);
    }

    // currently for test purpose
    public static void clearContexts() {
        contexts.clear();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getExtension(Class<T> type, String name) {
	    //根据name找
        for (ApplicationContext context : contexts) {
            if (context.containsBean(name)) {
                Object bean = context.getBean(name);
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());

        if (Object.class == type) {
            return null;
        }
        //根据类型查找
        for (ApplicationContext context : contexts) {
            try {
                return context.getBean(type);
            } catch (NoUniqueBeanDefinitionException multiBeanExe) {
                logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
            } catch (NoSuchBeanDefinitionException noBeanExe) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
                }
            }
        }

        logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");

        return null;
    }

}

Wrapper实现AOP

创建Wrapper

public class AdaptiveExtWrapper implements AdaptiveExtService {
    private AdaptiveExtService adaptiveExtService;

    //实现一个Wrapper类的关键就是提供一个带类似参数的构造函数
    public AdaptiveExtWrapper(AdaptiveExtService adaptiveExtService){
        this.adaptiveExtService = adaptiveExtService;
    }


    @Override
    public String run(String msg, URL url) {
        System.out.println("before");

        adaptiveExtService.run(msg, url);

        System.out.println("after");
        return "wrapper";
    }
}

DubboAdaptiveExt改造

public class DubboAdaptiveExt implements AdaptiveExtService {
    private AdaptiveExtService adaptiveExtService;

    public void setAdaptiveExtService(AdaptiveExtService adaptiveExtService) {
        this.adaptiveExtService = adaptiveExtService;
    }

    @Override
    public String run(String msg, URL url) {

        System.out.println(adaptiveExtService.run(msg, url));
        return "dubbo";
    }
}

修改文件,追加com.xyy.spi.dubbo.adaptive.AdaptiveExtWrapper:

dubbo=com.xyy.spi.dubbo.adaptive.DubboAdaptiveExt
cloud=com.xyy.spi.dubbo.adaptive.SpringCloudAdaptiveExt
thrift=com.xyy.spi.dubbo.adaptive.ThriftAdaptiveExt
com.xyy.spi.dubbo.adaptive.AdaptiveExtWrapper

测试类:

@Test
public void test7(){
    ExtensionLoader<AdaptiveExtService> loader = ExtensionLoader.getExtensionLoader(AdaptiveExtService.class);
    AdaptiveExtService adaptiveExtension = loader.getExtension("dubbo");
    URL url = URL.valueOf("http://localhost/xxx");
    adaptiveExtension.run("d", url);
}

运行输出:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLBob345-1646708612367)(AC0BE99EC0CE4BCC8889BF9AED600D1A)]

源码:

loadClass方法:

//是Wrapper类
else if (isWrapperClass(clazz)) {
    Set<Class<?>> wrappers = cachedWrapperClasses;
    if (wrappers == null) {
        cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
        wrappers = cachedWrapperClasses;
    }
    wrappers.add(clazz);
} else {

isWrapperClass(clazz)方法:

//存在构造,参数是type
private boolean isWrapperClass(Class<?> clazz) {
    try {
        clazz.getConstructor(type);
        return true;
    } catch (NoSuchMethodException e) {
        return false;
    }
}

createExtension 方法:

@SuppressWarnings("unchecked")
private T createExtension(String name) {
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null) {
        throw findException(name);
    }
    try {
        T instance = (T) EXTENSION_INSTANCES.get(clazz);
        if (instance == null) {
            EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
            instance = (T) EXTENSION_INSTANCES.get(clazz);
        }
        injectExtension(instance);
        //Wrapper类
        Set<Class<?>> wrapperClasses = cachedWrapperClasses;
        if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
            for (Class<?> wrapperClass : wrapperClasses) {
                //实例化,返回Wrapper类
                instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
            }
        }
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                type + ")  could not be instantiated: " + t.getMessage(), t);
    }
}

这样就调用了Wrapper类。
在这里插入图片描述

写到这里,本篇就结束了,让我们下一篇见!!!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值