原本没打算深究dubbo spi的,但源码中经常见到ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()这类代码,看的过程中如果不去搞清楚这些的话不太好理解整个过程
没办法,这懒是躲不过了,就花了点时间去看了下相关源码,代码本身不算复杂,就是稍微有点绕,一般人花点时间都能看懂。但不可能每次看到这些代码都去查看相关源码,这样太费时,且容易打断思路
因此做下相关逻辑笔记,便于自己后面查阅
主要分四块:实例、adaptive方法、wrapper、动态代理
实例
dubbo spi获取实例主要分下面这四个方法,均是获取实现了该接口的实例化对象
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)
返回的对象是interfaceName文件中name对应的class实例(目前没有该实例的话会创建)
ExtensionLoader.getExtensionLoader(Protocol.class).getLoadedExtension(name)
跟上面的区别就是如果还没创建就返回null
ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension()
获取接口@SPI标签中的值,然后以该值作为ke获取实例,也就是getExtension(spiVal)
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
这个有点特殊,如果加载的该接口所有子类中,没有@Adaptive标注的class,则会通过javassist创建一个interfaceName$Adaptive的类
也就是返回有两种情况:返回已有子类的实例(该class有@Adaptive) 返回自动创建的interfaceName$Adaptive实例
如AdaptiveExtensionFactory,AdaptiveCompiler就标注了@Adaptive,因此获取ExtensionFactory,Compiler对象不会动态创建类
方法
adaptive方式获取的实例,如果是自动创建的类interfaceName$Adaptive,调用其方法时,该方法在接口声明中必须有@Adaptive标签,否则不能调用
如:Protocol中有
int getDefaultPort()
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException
javassist创建的类实例不允许调用getDefaultPort,而可以调用export
interfaceName$Adaptive实例调用方法时,可以根据参数动态决定实际使用哪个子类实例
注:调用的方法参数中必须有一个是URL或者某个参数有getXX()方法获取URL的方法
根据url中方法获取name(默认值均为接口声明中@Adaptive的value)
获取规则:
1.接口为Protocol或者方法声明@Adaptive值为protocol,调用url.getProtocol()
2.方法中有参数类型为Invocation,调用url.getMethodParameter() 参数为方法声明中@Adaptive的value
3.其余调用url.getParameter() 参数为方法声明中@Adaptive的value
Wrapper
wrapper会对实例进行wrap之后再返回,也就是上面获取的对象进行封装之后再返回
是否会对对象进行封装,判断的依据是该接口的实现类中是否有以该接口类型为参数的构造器
如ProtocolFilterWrapper,ProtocolListenerWrapper,MockClusterWrapper,StubProxyFactoryWrapper分别会对Protocol,ProxyFactory,Cluster
非adaptive获取的Protocol,ProxyFactory,Cluster会进行wrap之后返回
无论是adaptive实例,子类实例,wrapper实例,初始化完成之后都会遍历该对象的方法通过set注入值(相当于spring中实例化后的populateBean)
动态代理
dubbo中动态代理有javassist跟jdk这两种,默认使用的是javassist,看源码的话可以先看JdkProxyFactory实现,然后再看JavassistProxyFactory
javassist方式主要是使用javassist创建了2个类,类信息概括如下
class Proxy0 extend Proxy
newInstance(InvocationHandler ih){return new interfaceImpl(ih)}
class interfaceImp0 implements interfaceA,interfaceB
Method[] methods;
InvocationHandler handler;
interfaceMethod(){return handler.invoke(this, methods[0], args)}
JavassistProxyFactory.getProxy方法中Proxy.getProxy(interface).newInstance(new InvocationHandler(invoker))返回的即为interfaceImp0实例