
本地服务暴露那我们注意点如果是dubbo我们应该用netty绑定一个端口这里最终会调用到 NettyServer#doOpenConsumer的订阅服务订阅入口来到关键入口类DefaultModuleDeployer#startSync 方法这里分两点1、是创建一个远程调用 invoke2、创建代理类我们先看第1点接口级订阅这里我们进入选择应用级订阅、接口级订阅、应用和接口级订阅 我们进入应用和接口级订阅首先进入接口级订阅最终会到 FailbackRegistry#subscribe上面是进行目录 创建有则忽略没有则创建 让后给子节点增加监听器最后将数据urls放到缓存应用级订阅这里我们进入选择应用级订阅、接口级订阅、应用和接口级订阅 我们进入应用和接口级订阅应用级订阅最终会调用到ServiceDiscoveryRegistry#doSubscribe这里面设计到两个关键点、1、获取接口对应的应用名称2、subscribedServices为接口所对应的应用名接下来就会取获取该应用的所有实例获取对应实例的元数据信息循环发送事件ServiceInstancesChangedEventServiceInstancesChangedListener#onEvent获取对应事件来获取对应的元数据信息这里我们重点分析一下从远端获取数据智能选择 接口级还是应用级如果应用级注册为空接口级注册不为空则是使用接口级注册如果接口级注册为空应用级注册不为空则是使用应用级注册如果接口级和应用级都不为空则用应用级创建代理类最终回到用到JavassistProxyFactoryDubboReference标注对象的引入我们看一下ReferenceAnnotationBeanPostProcessor的继承关系它继承BeanFactoryPostProcessor,所以他一定为实现postProcessBeanFactory后面会将DubboReference标注类对应的BeanDefinition进行实例化我们看一下对应class类ReferenceBean问题我们如果想往IOC容器中注入一个对象应该怎样处理使用Bean进行方法的标注 或者实现接口FactoryBean所以此时应该关注ReferenceBean#getObject所以在服务调用的时候才创建代理类进行调用Dubbo协议 服务调用服务端 启动过程深入分析我们查看一下服务启动的过程ProtocolFilterWrapper.export好我们进入DubboProtocol.export创建服务分析我们的Handler我们接着返回刚才位置下面的super方法里面会创建服务ChannelHandlers.wrap会对hander进一步包装1、我们进入ChannelHandlers.wrapMultiMessageHandler---HeartbeatHandler----AllChannelHandler - DecodeHandler - HeaderExchangeHandler - ExchangeHandlerAdapter我看看一下super创建服务NettyServerhandler - NettyServer - MultiMessageHandler---HeartbeatHandler----AllChannelHandler - DecodeHandler - HeaderExchangeHandler - ExchangeHandlerAdapter服务端调用过程我们知道请求过来通过Netty服务一定是Handler的处理,下面就是整个过程NettyServerHandler - NettyServer - MultiMessageHandler---HeartbeatHandler----AllChannelHandler - DecodeHandler - HeaderExchangeHandler - ExchangeHandlerAdapterNettyServerHandlerMultiMessageHandlerHeartbeatHandlerAllChannelHandler服务端线程模型 | Apache DubboDecodeHandlerHeaderExchangeHandlerExchangeHandlerAdapter这里是调用我们的目标invoker但是这里目标invoker被filter给包装了所以先要调用filter我们自定义过滤器就会在这里起作用调用完毕过滤器就会调用到AbstractProxyInvoker#invoke客户端调用会调用JavassistProxyFactory#getProxy获取代理类调用的时候一定会调用到InvokerInvocationHandler.invoker的方法调用过程会有容错负载均衡FailoverClusterInvoker#doInvoke我们可以简单看一下负载均衡HeaderExchangeChannel#request发送请求HeaderExchangeHandler#received处理返回数据Triple协议背景在Dubbo2.7中默认的是Dubbo协议因为Dubbo协议相比较于Http1.1而言Dubbo协议性能上是要更好的。但是Dubbo协议自己的缺点就是不通用假如现在通过Dubbo协议提供了一个服务那如果想要调用该服务就必须要求服务消费者也要支持Dubbo协议。而随着企业的发展往往可能会出现公司内部使用多种技术栈可能这个部门使用Dubbo另外一个部门使用Spring Cloud另外一个部门使用gRPC那此时部门之间要想相互调用服务就比较复杂了所以需要一个通用的、性能也好的协议这就是Triple协议。Triple协议介绍Triple 是 Dubbo3 提出的基于 HTTP2 的开放协议旨在解决 Dubbo2 私有协议带来的互通性问题。另外Google公司开发的gRPC也基于的HTTP2目前gRPC是云原生事实上协议标准包括k8s/etcd等都支持gRPC协议。HTTP1 和HTTP2进行对比HTTP1POST /getName HTTP/1.1 Host: example.com Content-Type: application/x-www-form-urlencoded Content-Length: 27 usernamejohnpassword1234我们会发现我们除了usernamejohnpassword1234 数据之外其他的内容都是额外信息并且这些额外信息量很大。HTTP2帧长度用三个字节来存一个数字这个数字表示当前帧的实际传输的数据的大小3个字节表示的最大数字是2的24次方16M所以一个帧最大为9字节16M。帧类型占一个字节可以分为数据帧和控制帧DATA用于传输请求和响应中的数据包含有效载荷payload。HEADERS用于传输HTTP头部信息包含有效载荷payload。PRIORITY用于指定数据流的优先级包含与数据流相关的信息。RST_STREAM用于指示数据流的中止并通知原因。SETTINGS用于传输HTTP/2连接的配置参数。PUSH_PROMISE用于服务端推送资源包含预期的请求头和有效载荷。PING用于检测HTTP/2连接的可用性和延迟时间。标志位占一个字节可以用来表示当前帧是整个请求里的最后一帧方便服务端解析、流标识符占4个字节在Java中也就是一个int不过最高位保留不用表示Stream ID这也是HTTP2的一个重要设计实际传输的数据Payload如果帧类型是HEADERS那么这里存的就是请求头如果帧类型是DATA 那么这里存的就是请求体通过这种设计我们可以发现我们就可以来压缩请求头了比如如果帧的类型是HEADERS 那就进行压缩当然压缩算法是固定的HPACK算法不能更换。Triple源码分析通过学习Dubbo协议我们首先要知道我们启动服务的应该是在TripleProtocol客户端处理调到TripleInvoker.doInvoke发送数据发送数据包括请求头和请求体发送请求头这里我们数据会放到队列最后会调用到HeaderQueueCommand#doSend方法发送数据放入队列先放到队列然后会定时flush的时候进行处理下面我们可以看到当我发现有数据就会一直取知道128个后才发送如果poll为空则走下面内容数据不为空则发送刷新后则调用到HeaderQueueCommand#doSend方法下面发送请求体和完成与上面发送请求头都是异步处理代码一样只是最后调用处理不同发送数据上图我们可以看出也是异步处理最终会调用到DataQueueCommand#doSend方法发送完成数据最终会调用感到EndStreamQueueCommand.doSend方法服务端启动进入启动Netty的源码这里有个处理器NettyPortUnificationServerHandler我们这里有的decode方法他会识别我们是不是HTTP2协议怎样识别HTTP2协议如果要建立的是一个HTTP2连接那么在建立完Socket连接后,客户端立刻会发送一个连接前言也就是一串字节(对应的字符串为:PRI*HTTP/2.0\r\n\r\nSM\r\n\r\n) 给到服务端服务端从而知道要建立的是HTTP2如果识别出RECOGNIZED处理数据处理请求头获取invoker启动监听器这里处理请求头获取了Invoker和对应的listener:UnaryServerCallListener 处理请求内容中会用到处理请求处理请求体这里只是给我们invoker设置了参数但是没有立刻调用而是在complete中进行调用处理完成帧扩展点SPI概念SPI是一种软件编程模型用于实现在运行时动态加载和扩展组件的能力。在Dubbo3中SPI机制被广泛应用于扩展框架功能允许用户自定义实现各种接口以满足业务需求。Java中的SPI机制我们使用Mybatis操作数据库那我们应该使用怎样操作mysql 或者oracle或者DB2呢 首先我们应该引入对应的Mysql的jar我们利用这jar才能操作数据库那对于JDBC操作DriveMananger获取链接的时候他怎样获取Mysql的jar包中对应的类来链接mysql呢实例加载对应的配置缺点我们如果对应配置文件中com.msb.dubbo.provider.SPI.JDK.Course配置多个实现类但是我们只需要EnglishCourse所以为了效率我们只应该加载EnglishCourse但是JDK的SPI会把所有的加载掉所以Dubbo退出自己的SPIDubbo3 SPI演示Wrapper包装AOP