本文共 7267 字,大约阅读时间需要 24 分钟。
package com.tan.spi.example;public interface People { void eat(String food);}
package com.tan.spi.example;public class Tom implements People{ @Override public void eat(String food) { System.out.print("Tom 在吃"+food); }}
package com.tan.spi.example;import java.util.Iterator;import java.util.ServiceLoader;public class Main { public static void main(String[] args) { System.out.print("llll"); ServiceLoaderload = ServiceLoader.load(People.class); Iterator iterator = load.iterator(); while (iterator.hasNext()) { People next = iterator.next(); next.eat("蛋糕"); } }}
src下面必须新建META-INF/services/接口全限定路径
结果截图 这里我们只是了解一下,具体还可以自行百度Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了
ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。
上面我们已经实验了java的spi,现在我们来看一下dubbo自定义实现的spi,这里有一个问题,dubbo为什么不用jdk的spi机制 而要自己定义一个???
dubbo spi 存储路径 META-INF/dubbo/internal 文件名为接口全路径名,每一个spi定义的格式为扩展名=具体类目
获取一个实现类的对象
getExtensionLoader(Class type) 为该接口new 一个ExtensionLoader,然后缓存起来
getAdaptiveExtension()
获取一个扩展装饰类对象,这个类有一个规则,如果没有一个adaptive注解,就会动态创建一个装饰类getExtension(String name)获取一个实现类的对象
首先看一下getExtensionLoader的源码,从 org.apache.dubbo.container.Container进去
private static final ExtensionLoaderloader = ExtensionLoader.getExtensionLoader(Container.class);
public staticExtensionLoader getExtensionLoader(Class type) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if (!type.isInterface()) { throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); } if (!withExtensionAnnotation(type)) { throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } // 这里是从一个ConcurrentMap中取,如果没有会将new 一个ExtensionLoader进去 ExtensionLoader loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader (type)); loader = (ExtensionLoader ) EXTENSION_LOADERS.get(type); } return loader; }
在看一下getAdaptiveExtension
这是adaptive注解/** * Provide helpful information for {@link ExtensionLoader} to inject dependency extension instance. * * @see ExtensionLoader * @see URL */ // ElementType.TYPE 代表该注解只能注解在类,包上面@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE, ElementType.METHOD})public @interface Adaptive { String[] value() default { };}
需要注意的是,adaptive注解和方法上是存在一定区别的:
注解在类上:代表人工实现编码,即实现了一个装饰类(设计模式中的装饰模式),比如ExtensionFactory 注解在方法上,代表动态的生成和编译一个动态的adaptive,例如Protoco$Adaptive 首先从**org.apache.dubbo.config.spring.schema.DubboNamespaceHandler(dubbo命名空间)**进去,看一下seviceBean.class@Override public void init() { registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true)); registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true)); registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true)); registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true)); registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true)); registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true)); registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true)); registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false)); registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser()); }
serviceBean实现了ServiceConfig,我们看一下这个方法,
发现里面的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 void loadDirectory(Map> extensionClasses, String dir, String type) { String fileName = dir + type; try { Enumeration 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(); loadResource(extensionClasses, classLoader, resourceURL); } } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
private void loadDirectory(Map> extensionClasses, String dir, String type) { // 拼装路径 String fileName = dir + type; try { Enumeration 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(); loadResource(extensionClasses, classLoader, resourceURL); } } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
转载地址:http://lnkgn.baihongyu.com/