ExtensionLoader<T>
—ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS //final static 存放class与ExtensionLoader对应关系
—ExtensionFactory objectFactory //当调用ExtensionLoader#injectExtension方法的时候进行依赖注入
—cachedAdaptiveClass //adaptive class如果@adaptive注解在类上,直接返回类,如果注解在方法上动态生成adaptive class
==========================dubbo SPI=====================================
—>getExtensionLoader(Class<T> type) //获取extentionload
—>T getAdaptiveExtension() //
—>createAdaptiveExtension()
—>injectExtension((T) getAdaptiveExtensionClass().newInstance()) //injecctExtension 依赖注入
—>getAdaptiveExtensionClass()
—>getExtensionClasses()
—>loadExtensionClasses() //获取type类的所有实现类,以及@SPI注解上的默认实现
—>loadDirectory(extensionClasses,META-INF/dubbo/internal, type.getName()); //获取路径下type的实现类放入extensionClasses Map中
—>loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL)
—>loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name)//@adaptive注解在类上cachedAdaptiveClass=clazz
—>createAdaptiveExtensionClass() //如果注解在方法上动态生成类
—>createAdaptiveExtensionClassCode() //生生代码
—>compiler.compile(code, classLoader) //生成class类
—>injectExtension((T)
—>objectFactory.getExtension(pt, property) //获取set方法需要的class
—>ExtensionLoader.getExtensionLoader(type).getAdaptiveExtension()
—>getExtensionLoader(Class<T> type) //获取extentionload
—>getExtension(String name) //获取SPI指定名称的实现类
—>createExtension(String name)
—>getExtensionClasses().get(name)//获取制定名称的类
—>injectExtension(instance)//给类的对象依赖注入
—>injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//ProtocolFilterWrapper ProtocolListenerWrapper装饰者模式一层层嵌入额外处理
总结: 使用adaptive这种机制,可以轻松拓展;
dubbo 内核对扩展是无感的 , 完全不知道扩展的存在 , 内核代码中不会出现使用具体扩展的硬编码。
========================dubbo 动态编译======================================
—>createAdaptiveExtensionClass()
—>createAdaptiveExtensionClassCode() //生成动态编译类的代码
—>compiler.compile(code, classLoader) //编译代码
动态编译生成的代码(取其中的一个方法)为:
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
org.apache.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(org.apache.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
}
=======================dubbo 与spring集成====================================
spring schema自定义拓展
1、编写自定义Schema文件;
2、编写自定义NamespaceHandler;
3、编写解析BeanDefinition的parser
4、在Spring中注册上述组建
dubbo通过自定义Schema是如何配置dubbo里面的核心组件
bubba-provider.xml文件内容:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- provider's application name, used for tracing dependency relationship -->
<dubbo:application name="demo-provider"/>
<!-- use multicast registry center to export service -->
<dubbo:registry address="zookeeper://10.199.4.108:2181,10.199.4.109:2181,10.199.4.110:2181,10.199.4.111:2181,10.199.4.112:2181"/>
<!-- use dubbo protocol to export service on port 20880 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- service implementation, as same as regular local bean -->
<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<!-- declare the service interface to be exported -->
<dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
</beans>
注:xmlns:dubbo="http://dubbo.apache.org/schema/dubbo中http://dubbo.apache.org/schema/dubbo为处理器类映射路径具体映射关系在spring.handlers中
spring.handlers文件内容为:
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
DubboNamespaceHandler类中定义各个配置的名称和实体类以及parse类比如:
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd 其中http://dubbo.apache.org/schema/dubbo/dubbo.xsd为
dubbo.xsd的文件映射路径,具体的映射关系在在spring.schemas文件中
spring.schemas文件内容为:
http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd
dubbo.xsd文件约束<dubbo>语法
=======================dubbo源码 服务暴露============================
serviceConfig———>获取ref(对外提供服务的实际类)
proxyFactory.geinvoker()——————————————————————————————————————————>invoker
protocol.export()————————————————————————————————————————————————————————————————————————————>exporter
服务暴露分为两个阶段
1、接口实现类转为invoker
spring schema标签里面的service—>serviceBean—>serviceConfig—>proxyFactory—>invoker
2、invoker转为exporter
本地暴露:protocol(inJvmprotocol)—>exporter—>存入exporterMap
—> ServiceConfig.export()
—>doExport()
—>appendProperties(this) //从配置文件中获取属性的value,然后为当前对象通过setter 方法来添加属性,完善serviceConfig的属性
—>doExportUrls
—>loadRegistries(true) //获取注册中心的地址
—>doExportUrlsFor1Protocol(protocolConfig, registryURLs)
—>appendParameters(map, application) //这个方法的作用就是通过调用当前对象的getter方法获取到传入对象的值然后塞到 map 当中去。用于后面的构造URL这个对象
—>new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map)
—>exportLocal(url)
—>protocol.export(invoker) //exporter持有invoker的引用,还持有exporterMap的引用. protocol由Protocol$Adaptive.getExtension(name)详解见@2
—>getInvoker(T proxy, Class<T> type, URL url) //invoker其实就是一个持有proxy,type,url的一个类,然后持有接口的动态代理类wrapper,重写doinvoke方法见@1
proxy对外提供的实际类ref,type当前接口的Class实例,URL 配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息
—>Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type) // //当前接口的代理对象Wrapper实例,动态代理的概念
exporters.add(exporter) //将exporter放入exporters Map中
注释***************
@1 return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
@2 这里的 protocol实例是 本地方法暴露获取的实例。它也是 dubbo 自定义的 SPI 生成的 Protocol$Adaptive通过它的getExtension(name)方法创建 Protocol实例
Protocol$Adaptive这个类生成的 Protocol对象的结构是:
.ProtocolListenerWrapper
.ProtocolFilterWrapper
.InjvmProtocol
dubbo 的定义 SPI 里面包括 AOP,其实就是获取到所有的 SPI 接口的实例对象
远程暴露:protocol(DubboProtocol)—>HeaderExchanger—>NettyTransporter—>ZookeeperRegister—>exporter—>存入exporterMap
—> ServiceConfig.export()
—>doExport()
—>appendProperties(this) //从配置文件中获取属性的value,然后为当前对象通过setter 方法来添加属性,完善serviceConfig的属性
—>doExportUrls
—>loadRegistries(true) //获取注册中心的地址
—>doExportUrlsFor1Protocol(protocolConfig, registryURLs)
—>appendParameters(map, application) //这个方法的作用就是通过调用当前对象的getter方法获取到传入对象的值然后塞到 map 当中去。用于后面的构造URL这个对象
—>new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map)
—>proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()))
—>new DelegateProviderMetaDataInvoker(invoker, this)
—>protocol.export(wrapperInvoker) //protocol通过Protocol$Adaptive的getExtension(name)获取 此时name为registry
—>doLocalExport(originInvoker)
—>getCacheKey(originInvoker)//通过 Invoker 对象获取到缓存 key,然后再删除 dynamic与enabled 参数
—>getProviderUrl(originInvoker)
—>providerUrl.removeParameters("dynamic", "enabled").toFullString()
—>(ExporterChangeableWrapper<T>) bounds.get(key) //bounds缓存中根据上面获取的 key 获取 Exporter 对象,如果获取到直接返回;否则进行服务暴露(下面三行)
ExporterChangeableWrapper持有Invoker,Exporter的引用
—>new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker))
—>new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker)//protocol为dubboProtocol
—>invoker.getUrl()
—>serviceKey(url)
—>new DubboExporter<T>(invoker, key, exporterMap)
—>exporterMap.put(key, exporter)
—>openServer(url) //DubboProtocol#createServer 创建服务,达到服务暴露的目的
—>createServer(url) //创建一个 Netty Serve 服务
—>Exchangers.bind(url, requestHandler)
—>ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type).bind(url, requestHandler)
—>new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))))
—>Transporters.bind(URL url, ChannelHandler... handlers)
—>getTransporter().bind(url, handler)
—>ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension().bind(url, handler) //NettyTransport
—>new NettyServer(url, listener) //打开nettyServer
—>bounds.put(key, exporter) //
—>getRegistry(originInvoker) //
—>getRegistryUrl(originInvoker)
—>registryFactory.getRegistry(registryUrl) //AbstractRegistryFactory.getRegistry
—>url.setPath(RegistryService.class.getName())
.addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
.removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY) //添加参数interface为com.alibaba.dubbo.registry.RegistryService并去掉export参数
—>createRegistry(url) //ZookeeperRegistryFactory#createRegistry创建 ZookeeperRegistry 实例
—>zookeeperTransporter.connect()
—>AbstractRegistry(URL url) //AbstractRegistry构造函数中中调用loadProperties(),在以下目录中保存注册信息 .dubbo\dubbo-registry-127.0.0.1.cache
—>FailbackRegistry(URL url) //创建线程池 ScheduledExecutorService 检测并连接注册中心,如果失败就就调用 retry()进行重连,高可用
—>zookeeperTransporter.connect()
—>exporters.add(exporter)
=======================dubbo源码 服务引用============================
1、把远端服务转化为invoker
2、将invoker转化为客户端需要的接口
—>ReferenceConfig.createProxy(Map<String, String> map) //
—>loadRegistries(false) //加载注册中心配置,因为 dubbo 支持多配置中心,所以返回 URL 的集合
—>refprotocol.refer(interfaceClass, urls.get(0)) //Protocol$Adaptive 通过注册中心 URL 与 接口 Class 创建 Invoker 调用对象
—>RegistryProtocol.refer(Class<T> type, URL url)
—>registryFactory.getRegistry(url) //获取到 zookeeper 注册中心
—>doRefer(cluster, registry, type, url)
—>new RegistryDirectory<T>(type, url) //创建注册服务目录 RegistryDirectory
—> registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY,
Constants.CHECK_KEY, String.valueOf(false))) //注册服务消费者 URL 到 zookeeper,其实就是创建 zookeeper 的节点
—>directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY,
Constants.PROVIDERS_CATEGORY
+ "," + Constants.CONFIGURATORS_CATEGORY
+ "," + Constants.ROUTERS_CATEGORY))//订阅 zookeeper结点,当服务发生变更时,销毁无效的 Invoke.
—>DubboProtocol.refer(Class<T> serviceType, URL url)
—>new DubboInvoker<T>(serviceType, url, getClients(url), invokers) //获取DubboInvoker对象
—>getClients(url)
—>new ExchangeClient[connections] //
—>HeaderExchangeClient(Client client, boolean needHeartbeat)
—>startHeartbeatTimer() //开启心跳
—>invokers.add(invoker) //将创建的 invoker (服务调用者)返回给目录服务,用来刷新 RegistryDirectory 中的Map<String, List<Invoker<T>>> methodInvokerMap对象
—>cluster.join(directory) //合并 invoker 创建并提供集群 failover (故障转移)调用策略 MockClusterInvoker
—>proxyFactory.getProxy(invoker) //通过代理工厂创建远程服务代理返回给使用者
—>AbstractProxyFactory.getProxy(Invoker<T> invoker, boolean generic) //
—>JavassistProxyFactory.getProxy(Invoker<T> invoker, Class<?>[] interfaces)
—>return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
—>InvokerInvocationHandler.invoke(Object proxy, Method method, Object[] args)
—>new RpcInvocation(method, args)
—> invoker.invoke(invocation).recreate()
—>MockClusterInvoker.invoke(Invocation invocation)
—>FailoverClusterInvoker.doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) //
—>DubboInvoker.doInvoke(final Invocation invocation)
—>return (Result) currentClient.request(inv, timeout).get()
======================dubbo源码 Listener & Filter ================================
—>ProtocolFilterWrapper. export(Invoker<T> invoker)
—>protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER))
—>ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group) //获取所有的filter
—> for (int i = filters.size() - 1; i >= 0; i--) //循环filter
—>filter.invoke(next, invocation) //将filter包装成一个链 代码见注释@1
注释***************
@1 private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
================================dubbo源码分析 集群容错 Invoke===========================
—>MockClusterInvoker.invoke(Invocation invocation)
—>AbstractClusterInvoker.invoke(final Invocation invocation)
—>list(invocation) //获取 List<Invoker<T>>
—>directory.list(invocation)
—>ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE)) //获取loadbalance
—>doInvoke(invocation, invokers, loadbalance)
===============================dubbo中的设计模式===========================================
工厂模式 dubboSPI
装饰器模式 AOP,IOC
责任链模式 多filter链式组合
观察者模式 zk上的listener