一.SPI(service provider interface)
JAVA SPI(JDK内置服务发现机制,用于动态扩展)
JDK定义接口规范:com.xxx.xxx.Driver
其他厂商根据结构规范实现实现类:com.mysql.jdbc.Driver(implement Driver)
文件位置:resources/META-INF/services/com.xxx.xxx.Driver(接口全路径)
文件内容:com.mysql.jdbc.Driver(实现类路径)
缺点:
1.全部加载
2.加载失败会报错
DUBBO SPI
1.文件位置:/META-INF/dubbo;/META-INF/dubbo/internal;/META-INF/services
2.文件名:同java spi
3.内容:key=value
二.Dubbo SPI实现
@SPI
表示当前接口是一个扩展点,可以自己扩展实现,默认扩展点是DubboProtocol
@Adaptive
定义在类级别表示自适应适配器
定义在方法级别表示需要动态加载生成一个适配器
Extension.getExtensionLoader(Protocol.class).getExtension(“dubbo”);
Protocol protocol = Extension.getExtensionLoader(Protocol.class).getAdaptiveExtension();
Extension.getExtensionLoader.getAdaptiveExtension
getExtensionLoader(通过一个Class参数去获
得一个ExtensionLoader对象,有点类似一个工厂模式)
getAdaptiveExtension(去获得一个自适应的扩展点)
createAdaptiveExtension
injectExtension(可以实现扩展点的注入)
getAdaptiveExtensionClass
createAdaptiveExtensionClass(动态创建一个扩展点,生成Protocol$Adaptive)
getExtensionClasses(加载所有路径下的扩展点)
loadExtensionClasses(加载dubbo spi路径下的扩展点)
三.服务发布流程
记录下整体调用流程,没有太详细的解释,可以自己debug调用下看结果
1.解析spring配置文件
spring支持:/META-INF/spring.handlers定义了xml解析类DubboNamespaceHandler
/META-INF/spring.schemas定义了xsd文件dubbo.xsd
2.DubboNamespaceHandler.init()调用DubboBeanDefinitionParser对spring标签进行解析
new DubboBeanDefinitionParser(ServiceBean.class, true)
3.ServiceBean进行服务发布做了两件事1)通过netty启动了一个服务监听2)通过zookeeper注册了一个协议地址
ServiceBean实现了InitializingBean,初始化时会调用afterPropertiesSet()方法
ServiceBean.afterPropertiesSet()
1.将解析的xml属性set到对应属性里
2.ServiceConfig.export()-->doExport()-->doExportUrls()-->doExportUrlsFor1Protocol()-->protocol.export(invoker)
ServiceConfig.export():判断是否delay来决定是否Thread.sleep(),调用doExport
doExport():做相应检查校验,调用doExportUrls
doExportUrls():加载注册地址,循环调用doExportUrlsFor1Protocol
doExportUrlsFor1Protocol():通过多种方式获得host,将属性put到map中,把map中地址转为URL,调用protocol.export(invoker)进行服务发布
protocol === Protocol$Adaptive
因为是registryURL
protocol.export==Protocol$Adaptive.export==ExtensionLoader.getExtensionLoader.getExtension("")==RegistryProtocol.export
invoker = proxyFactory.getInvoker()
proxyFactory = ProxyFactory&Adaptive ==JavassistProxyFactory
JavassistProxyFactory.getInvoker()
Wrapper.getWrapper()
Wrapper.makeWrapper()
invoker = Wrapper.makeWrapper() = JavassistProxyFactory
protocol.export(invoker):将invoker发布出去放到网络层
invoker:
wrapper(JavassistProxyFactory)
proxy(代理,发布接口的实现类)
type(接口,发布的接口地址)
url(registry://开头的url)
4.RegistryProtocol
1)RegistryProtocol.export().doLocalExport(orginInvoker)本地发布,启动服务
1.1)Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
由于protocol是注入的,所以:
protocol = ProtocolFilterWrapper(ProtocolListenerWrapper(DubboProtocol))
依次调用相应类的export方法
ProtocolFilterWrapper.export
buildInvokerChain:形成filter链
ProtocolListenerWrapper.export
DubboProtocol.export
1.2)exporter = new ExporterChangeableWrapper<T>((Exporter<T>)protocol.export(invokerDelegete), originInvoker);
2)registry = getRegistry(originInvoker);
将registryUrl === registry://转换为registryUrl ===zookeeper://
RegistryFactory 是注入的扩展点 --> RegistryFactory$Adaptive --> ZookeeperRegistryFactory
ZookeeperRegistryFactory.getRegistry --> ZookeeperRegistry
3)registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
订阅监听