总体思路
1、解析dubbo的xml文件或注解
2、服务的发布
3、启动netty服务
1、Dubbo对于spring标签的扩展
spring标签的扩展简介
【1】、创建一个需要扩展的组件
创建一个普通POJO类,该类主要是用来接收配置文件属性
【2】、定义一个XSD文件描述组件内容。
定义一个XSD文件描述组件内容。
targetNamespace:来自什么命名空间。如:targetNamespace="http://www.lw.com/schema/user"
elementFormDefault="qualified":要求xml文档的每一个元素都要有命名空间指定。
【3】、创建一个类,该类实现BeanDifinitionParser接口,主要用来解析XSD文件中的定义和组件的定义;
class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser。
重新protected void doParse(Element element, BeanDefinitionBuilder builder)方法。作用从Element中解析并提取对应的元素,并放入到BeanDefinitionBuilder中,【待】bean的解析后统一注册到beanFactory中。如:builder.addPropertyValue("username", username);
【4】、创建一个NamespaceHandler类,该类扩展NamespaceHandlerSupport,主要作用是将组件注册到spring的容器中
class MyNamespaceHandler extends NamespaceHandlerSupport。重写public void init()方法。作用:将组件注册到spring容器中。如:registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
【5】、编写spring.handlers和spring.schemas文件
spring.handlers内容http\://www.lw.com/schema/user=com.lw.spring.MyNamespaceHandler
命名空间=自定义处理器的类全名
spring.schemas内容http\://www.lw.com/schema/user.xsd=com/lw/spring/user.xsd
自定义标签XSD的URL=自定义标签XSD在工程中的具体位置
6、来源:https://blog.youkuaiyun.com/weixin_34026276/article/details/91663325
dubbo实现spring标签的扩展
ServiceBean的实现
通过6个接口和一个父类实现的
【1】、InitializingBean#afterPropertiesSet接口作用:
接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。被重写的方法为afterPropertiesSet【2】、DisposableBean#destroy接口的作用:
被重写的方法为destroy,bean被销毁的时候,spring容器会自动执行destory方法,比如释放资源【3】、ApplicationContextAware#setApplicationContext接口的作用
实现了这个接口的bean,当spring容器初始化的时候,会自动的将ApplicationContext注入进来【4】、ApplicationListener#onApplicationEvent接口的作用
ApplicationEvent事件监听,spring容器启动后会发一个事件通知。被重写的方法为:onApplicationEvent,onApplicationEvent方法传入的对象是ContextRefreshedEvent。这个对象是当Spring的上下文被刷新或者加载完毕的时候触发的。因此服务就是在Spring的上下文刷新后进行导出操作的 【5】、BeanNameAwar的作用 获得自身初始化时,本身的bean的id属性,被重写的方法为setBeanName 【6】、ApplicationEventPublisherAware的作用
02、服务的发布【dubbo协议为例】
【1】、ServiceBean#afterPropertiesSet方法
dubbo中配置的application、registry、service、protocol等信息,加载到相应的config实体中。便于以后的使用。
【2】、ServiceBean#onApplicationEvent方法
服务发布事件的入口。spring容器启动后会收到一个事件通知,也就是会调用里面的程序。其中判断服务是否发布、如果没有发布则调用export方法,发布服务。
【3】、ServiceBean#export方法
重写了父类ServiceConfig的export方法,并调用父类的export方法supper.export();发布服务
【4】、ServiceConfig#export方法
检查并更新配置文件信息,判断服务是否需要发布,是否延迟发布。再调用doExport方法。
【5】、ServiceConfig#doExport方法
判断服务是否发布过了,设置发布状态和服务路径。再调用doExportUrls方法
【6】、ServiceConfig#doExportUrls方法
将所有注册中心的信息封装再URL的list集合内,遍历所有配置的协议,实例化ProviderModel服务的元数据,再调用
doExportUrlsFor1Protocol方法
【7】、ServiceConfig#doExportUrlsFor1Protocol方法
当前服务下所配置的<dubbo:method>参数进行解析,保存到map集合中。
获得当前服务需要暴露的ip和端口
组装URL为dubbo协议的URL
发布服务为本地local和远程remote
local略
remote发布服务
【8】、ServiceConfig#doExportUrlsFor1Protocol中的protocol.export
通过ExtensionLoader得到协议的扩展对象。如下:
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
为Protocol$Adaptive
【9】、ServiceConfig#doExportUrlsFor1Protocol中的protocol.export中的Protocol$Adaptive
根据Invoker实例中的url判定registry://协议。故因此调用RegistryProtocol.export方法
【10】、ServiceConfig#doExportUrlsFor1Protocol中的protocol.export中的Protocol$Adaptive中的RegistryProtocol.export
获得zookeeper注册中心的url:zookeeper://ip:port
获得服务提供者的url: dubbo://ip:port...
调用doLocalExport方法去暴露服务
【11】、RegistryProtocol.export方法中的doLocalExport方法
(Exporter<T>) protocol.export(invokerDelegate)
【12】、protocol为Protocol$Adaptive
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
//extension 为一个Wrapper的包装类
QosProtocolWrapper/ProtocolListenerWrapper/ProtocolFilterWrapper/DubboProtocol
extension.export(arg0);
【13】、SPI的Wrapper包装
QosprotocolWrapper:在线运维命令
ProtocolFilterWrapper:对invoker进行filter的包装,实现请求的过滤
ProtocolListenerWrapper:export时候插入监听机制
【14】、ProtocolFilterWrapper【重点】
这个是一个过滤器的包装,使用责任链模式,对invoker进行了包装
【15】、DubboProtocol#export
调用openServer(url);//启动服务
【16】、DubboProtocol#openServer
开启一个服务,并将服务存入缓存中,如果缓存中没有则调用createServer
【17】、DubboProtocol#createServer
创建服务,开启心跳检测,默认使用netty。组装url,创建ExchangeServer。通过Exchangers.bind(url, requestHandler)方法。
【18】、Exchangers.bind
获取Exchanger,默认为HeaderExchanger。
getExchanger(url).bind(url, handler)方法获取ExchangeServer 实例
【19】、headerExchanger.bind
调用Transporters.bind方法获取Server实例
【20】Transporters.bind
调用NettyServer(url, listener);
【21】、NettyServer
初始化一个nettyserver,并且从url中获得相应的ip/ port。然后调用doOpen();
【22】、doOpen
开启netty