一、SPI
引入:spi标准:
1、需要在 classpath 下创建一个目录,该目录命名必须是:META-INF/service
2、在该目录下创建一个 properties 文件,该文件需要满足以下几个条件 :
2.1 文件名必须是扩展的接口的全路径名称
2.2 文件内部描述的是该扩展接口的所有实现类
2.3 文件的编码格式是 UTF-8
3、通过 java.util.ServiceLoader 的加载机制来发现
spring加载器---SpringfactoryLoader
dubbo加载器---ExtentionLoader;
dubbo的spi过程:
文件路径为@SPI注解标记的全路径名:com.test.dubbo
内容为接口的实现类(key-value):mydubbo=com.test.dubbo.mydubbo
服务启动时,会加载约定的配置classpath下的全类路径的文件,并通过ExtentionLoader会将所有的实现类以key-value的形式放进一个map,当扫面到@Spi(“mydubbo”)(---接口必须要有这个注解和具体的value),会从缓存的map内,取出我们需要的实现类,【默认是@Spi(“dubbo”)具体执行ExtensionLoader.getExtensionLoader.getExtension】
多个实现类 ,可以通过URL或者@Adaptive 来具体调用:
1、@Adaptive主要用于在spi多个实现类中找一个数据合适的扩展实现,只能一个实现类用该注解;
2、方法层面:放在SPI接口的方法上@Adaptive注解中的value属性,才会被处理生效;可以再方法上增加@Adaptive注解,注解中的value与链接中的参数的key一致,链接中的key对应的value就是spi中的name[mydubbo],获取相应的实现类
@SPI("dubbo")publicinterface AdaptiveExt2 {@Adaptive({"t"})
String echo(String msg, URL url);}
@Testpublicvoidtest1(){
ExtensionLoader<AdaptiveExt> loader =ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test?t=mydubbo");
System.out.println(adaptiveExtension.echo("d", url));}
具体可以参看: Dubbo SPI之Adaptive详解 - 简书
其他:rpc远程过程调用,负载均衡,重试机制,客户端缓存,zookeeper注册中心;
二、服务暴露\引用
引入:Springboot启动监听器的 ,待Spring容器refresh之后,开始执行callrunner,运行器触发dubbo的服务开始注册,暴露,发现等
暴露和注册:第一步将持有的服务实例通过代理转换成 Invoker, 第二步会把 Invoker 通过具体的协议 ( 比如 Dubbo ) 转换成 Exporter,
详细:provider通过serveceBean,实际是serviceConfig 的export()方法,内部通过proxyFactory的createinvoker()获取invoker,然后调用protocol的exported()方法,执行init()得到最后的exporter,最后注册到注册中心;
详细流程时序图:

发现引用:第一步通过持有远程服务实例生成Invoker, 这个 Invoker 在客户端是核心的远程代理对象 。 第二步会把 Invoker 通过动态代理转换成实现用户接口的动态代理引用
详细:consumer通过ReferenceBean,实际是ReferenceConfigre的refer()方法,内部调用RegistryProtocol的refer(),并调用Registry的subscribe()进行订阅,然后调用Protocol 的refer(),执行init()取得invoker,然后通过ProxyFactory的createproxy()获得需要用的接口代理类
详细流程时序图:
