有了确定的协议,服务名,服务参数后,⾃然就可以组装成服务的URL了。
但是还有⼀点是⾮常重要的,在Dubbo中⽀持服务动态配置,注意,这个和配置中⼼不是同⼀概念,动态配置是可以在服务导出后动态的去修改服务配置的 。 动态配置,其实就是继续给服务增加了⼀些参数,所以在把服务的URL注册到注册中⼼去之前,得先按照动态配置中所添加的配置重写⼀下URL,也就是应⽤上动态配置中的参数。 只有这样作完之后得到的URL才是真正准确的服务提供者URL。 将服务URL注册到注册中⼼去 有了准确的服务URL之后,就可以把URL注册到注册中⼼上去了。 4 这个步骤并不麻烦,只不过这⾥要去寻找⽤户是否配置了多个注册中⼼,将服务URL注册到每个注册中⼼去。 根据服务URL启动Server在服务URL中指定了协议,⽐如Http协议、Dubbo协议。根据不同的协议启动对应的Server。 ⽐如Http协议就启动Tomcat、Jetty。 ⽐如Dubbo协议就启动Netty。
不能只启动Server,还需要绑定⼀个RequestHandler,⽤来处理请求。 ⽐如,Http协议对应的就是InternalHandler。Dubbo协议对应的就是ExchangeHandler。
这⾥来详细分析⼀下Dubbo协议所启动的Server。 1. 调⽤DubboProtocol的openServer(URL url)⽅法开启启动Server 2. 调⽤DubboProtocol的createServer(url)⽅法,在createServer()⽅法中调⽤Exchangers.bind(url, requestHandler)得到⼀个ExchangeServer 3. 其中requestHandler表示请求处理器,⽤来处理请求 4. 在Exchangers.bind(url, requestHandler)中,先会根据URL得到⼀个Exchanger,默认为 HeaderExchanger 5. HeaderExchanger中包括HeaderExchangeClient、HeaderExchangeServer 6. HeaderExchangeClient负责发送⼼跳,HeaderExchangeServer负责接收⼼跳,如果超时则会关闭channel 7. 在构造HeaderExchangeServer之前,会通过调⽤Transporters. bind (url, new DecodeHandler(new HeaderExchangeHandler(handler)))⽅法的到⼀个Server 8. 默认会使⽤getTransporter去bind(URL url, ChannelHandler listener)从⽽得到⼀个Servlet,此时 的listener就是外部传进来的DecodeHandler 9. 在NettyTransporter的bind⽅法中会去new NettyServer(url, listener),所以上⾯返回的Server默认就是NettyServer 10. 在构造NettyServer时,会调⽤ChannelHandlers.wrap(handler,ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME))再构造⼀个ChannelHandler。 11. wrap中的handler就是上⾯的listener 12. 在wrap⽅法中会调⽤new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class).getAdaptiveExtens ion().dispatch(handler, url)));构造⼀个ChannelHandler。 13. 构造完ChannelHandler后,就是真正的去开启Server了,会调⽤AbstractServer抽象类的doOpen⽅法。 14. 在NettyServer中,会实现doOpen⽅法,会调⽤new NettyServerHandler(getUrl(), this)构造⼀个NettyServerHandler,并bind地址 15. ⾄此,DubboProtocol协议的启动Server流程就结束。 总结⼀下DubboProtocol协议的RequestHandler链路: 1. NettyServerHandler:与NettyServer直接绑定的请求处理器,负责从Netty接收到请求, channelRead()⽅法获取到请求,然后调⽤下⼀层的Handler(NettyServer)的received()⽅法将请求传递下去,此时的请求还是Object msg 2. NettyServer:NettyServer的⽗类AbstractPeer中存在received(),该⽅法没有做什么,直接把msg传递给下⼀层Handler(MultiMessageHandler) 3. MultiMessageHandler:此Handler会判断msg是否是⼀个MultiMessage,如果是,则对 MultiMessage进⾏拆分,则把拆分出来的msg传递给下层Handler(HeartbeatHandler),如果不 是,则直接把msg传递给下层Handler(HeartbeatHandler) 4. HeartbeatHandler:此Handler通过received()⽅法接收到msg,然后判断该msg是不是⼀个⼼跳请求或⼼跳响应,如果是⼼跳请求,则此Handler返回⼀个Response对象(很简单的⼀个对象),如果是⼼跳响应,则打印⼀个⽇志,不会有其他逻辑,如果都不是,则把msg传递给下层 Handler(AllChannelHandler)。 5. AllChannelHandler:此Handler通过received()⽅法接收到msg,然后把msg封装为⼀个 ChannelEventRunnable对象,并把ChannelEventRunnable扔到线程池中去,异步去处理该msg。在ChannelEventRunnable中会把msg交给下⼀个Handler(DecodeHandler) 6. DecodeHandler:此Handler通过received()⽅法接收到msg,会对msg解析decode解码,然后交给下⼀个Handler(HeaderExchangeHandler) 7. HeaderExchangeHandler:此Handler通过received()⽅法接收到msg,会判断msg的类型 a. 如果Request是TwoWay,则会调⽤下⼀个Handler(DubboProtocol中的requestHandler)的 reply⽅法得到⼀个结果,然后返回; b. 如果Request不是TwoWay,则会调⽤下⼀个Handler(DubboProtocol中的requestHandler)的 received⽅法处理该请求,不会返回结果 8. requestHandler:此Handler是真正的处理请求逻辑,在received()⽅法中,如果msg是Invocation,则会调⽤reply⽅法,但不会返回reply⽅法所返回的结果,在reply⽅法中把msg强制转换为Invocation类型 inv,然后根据inv得到对应的服务Invoker,然后调⽤invoke(inv)⽅法,得到结果。 服务导出源码流程 1. ServiceBean.export()⽅法是导出的⼊⼝⽅法,会执⾏ServiceConfig.export()⽅法完成服务导出,导出完了之后会发布⼀个Spring事件ServiceBeanExportedEvent 2. 在ServiceConfig.export()⽅法中会先调⽤checkAndUpdateSubConfigs(),这个⽅法主要完成 AbstractConfig的参数刷新(从配置中⼼获取参数等等),AbstractConfig是指ApplicationConfig、 ProtocolConfig、ServiceConfig等等,刷新完后会检查stub、local、mock等参数是否配置正确 3. 参数刷新和检查完成了之后,就会开始导出服务,如果配置了延迟导出,那么则按指定的时间利⽤ScheduledExecutorService来进⾏延迟导出 4. 否则调⽤doExport()进⾏服务导出 5. 继续调⽤doExportUrls()进⾏服务导出 6. ⾸先通过loadRegistries()⽅法获得所配置的注册中⼼的URL,可能配了多个配置中⼼,那么当前所导出的服务需要注册到每个配置中⼼去,这⾥,注册中⼼是以URL的⽅式来表示的,使⽤的是什么注册中⼼、注册中⼼的地址和端⼝,给注册中⼼所配置的参数等等,都会存在在URL上,此URL以registry://开始 7. 获得到注册中⼼的registryURLs之后,就会遍历当前服务所有的ProtocolConfig,调⽤ doExportUrlsFor1Protocol(protocolConfig, registryURLs);⽅法把当前服务按每个协议每个注册中 ⼼分别进⾏导出 8. 在doExportUrlsFor1Protocol()⽅法中,会先构造⼀个服务URL,包括 a. 服务的协议dubbo://, b. 服务的IP和PORT,如果指定了就取指定的,没有指定IP就获取服务器上⽹卡的IP, c. 以及服务的PATH,如果没有指定PATH参数,则取接⼝名 d. 以及服务的参数,参数包括服务的参数,服务中某个⽅法的参数 e. 最终得到的URL类似: dubbo://192.168.1.110:20880/com.tuling.DemoService? timeout=3000&&sayHello.loadbalance=random 9. 得到服务的URL之后,会把服务URL作为⼀个参数添加到registryURL中去,然后把registryURL、服务的接⼝、当前服务实现类ref⽣成⼀个Invoker代理对象,再把这个代理对象和当前ServiceConfig对象包装成⼀个DelegateProvidermetaDataInvoker对象,DelegateProvidermetaDataInvoker就表示了完整的⼀个服务 10. 接下来就会使⽤Protocol去export导出服务了,导出之后将得到⼀个Exporter对象(该Exporter对象,可以理解为主要可以⽤来卸载(unexport)服务,什么时候会卸载服务?在优雅关闭Dubbo应⽤的时候) 11. 接下来我们来详细看看Protocol是怎么导出服务的? 12. 但调⽤protocol.export(wrapperInvoker)⽅法时,因为protocol是Protocol接⼝的⼀个Adaptive对 象,所以此时会根据wrapperInvoker的genUrl⽅法得到⼀个url,根据此url的协议找到对应的扩展点,此时扩展点就是RegistryProtocol,但是,因为Protocol接⼝有两个包装类,⼀个是 ProtocolFilterWrapper、ProtocolListenerWrapper,所以实际上在调⽤export⽅法时,会经过这两 个包装类的export⽅法,但是在这两个包装类的export⽅法中都会Registry协议进⾏了判断,不会做过多处理,所以最终会直接调⽤到RegistryProtocol的export(Invoker< T > originInvoker)⽅法 13. 在RegistryProtocol的export(Invoker< T > originInvoker)⽅法中,主要完成了以下⼏件事情: a. ⽣成监听器,监听动态配置中⼼此服务的参数数据的变化,⼀旦监听到变化,则重写服务URL,并且在服务导出时先重写⼀次服务URL b. 拿到重写之后的URL之后,调⽤doLocalExport()进⾏服务导出,在这个⽅法中就会调⽤ DubboProtocol的export⽅法去导出服务了,导出成功后将得到⼀个ExporterChangeableWrapper i. 在DubboProtocol的export⽅法中主要要做的事情就是启动NettyServer,并且设置⼀系列的 RequestHandler,以便在接收到请求时能依次被这些RequestHandler所处理 ii. 这些RequestHandler在上⽂已经整理过了 c. 从originInvoker中获取注册中⼼的实现类,⽐如ZookeeperRegistry d. 将重写后的服务URL进⾏简化,把不⽤存到注册中⼼去的参数去除 e. 把简化后的服务URL调⽤ZookeeperRegistry.registry()⽅法注册到注册中⼼去 f. 最后将ExporterChangeableWrapper封装为DestroyableExporter对象返回,完成服务导出 Exporter架构 ⼀个服务导出成功后,会⽣成对应的Exporter: 1. DestroyableExporter:Exporter的最外层包装类,这个类的主要作⽤是可以⽤来unexporter对应的服务 2. ExporterChangeableWrapper:这个类主要负责在unexport对应服务之前,把服务URL从注册中⼼中移除,把该服务对应的动态配置监听器移除 3. ListenerExporterWrapper:这个类主要负责在unexport对应服务之后,把服务导出监听器移除 4. DubboExporter:这个类中保存了对应服务的Invoker对象,和当前服务的唯⼀标志,当NettyServer接收到请求后,会根据请求中的服务信息,找到服务对应的DubboExporter对象,然后从对象中得到Invoker对象 服务端Invoker架构1. ProtocolFilterWrapper$CallbackRegistrationInvoker:会去调⽤下层Invoker,下层Invoker执⾏完了之后,会遍历过滤器,查看是否有过滤器实现了ListenableFilter接⼝,如果有,则回调对应的
onResponse⽅法,⽐如TimeoutFilter,当调⽤完下层Invoker之后,就会计算服务的执⾏时间 2. ProtocolFilterWrapper$1:ProtocolFilterWrapper中的过滤器组成的Invoker,利⽤该Invoker,可以执⾏服务端的过滤器,执⾏完过滤器之后,调⽤下层Invoker 3. RegistryProtocol$InvokerDelegate:服务的的委托类,⾥⾯包含了 DelegateProvidermetaDataInvoker对象和服务对应的providerUrl,执⾏时直接调⽤下层Invoker 4. DelegateProvidermetaDataInvoker:服务的的委托类,⾥⾯包含了AbstractProxyInvoker对象和 ServiceConfig对象,执⾏时直接调⽤下层Invoker 5. AbstractProxyInvoker:服务接⼝的代理类,绑定了对应的实现类,执⾏时会利⽤反射调⽤服务实现类实例的具体⽅法,并得到结果


