同步操作将从 Ticsmyc/T_RPC_Framework 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
[TOC]
与Spring整合后, 服务端的服务注册想用注解实现。
最开始使用的是applicationContext.getBeansWithAnnotation 这个方法。 在容器中的bean都实例化完毕后,又调用ApplicationContext的相关方法, 获取到所有标识了指定注解的bean,做服务发布。 无形中导致bean的两次遍历。
后来优化成使用BeanPostProcessor,在Bean实例化时就进行发布。
通过定义协议,完美避免了。。。
fun.ticsmyc.rpc.client.transport.netty.NettyRpcClient的 45-53 行
客户端发送请求的方式: 先根据请求方法和所在的组,从nacos获取到服务提供者的ip和端口。 然后使用netty发起网络请求。
最初重试机制放在了拿到ip端口之后, 如果连接不成功,会重复连接。感觉也没什么问题。
测试时发现, 由于nacos的延迟,当服务提供者频繁上下线时,nacos中的信息不会及时更新,导致客户端拿到的ip和端口是过期的,多次重试仍连接不上。
最后修改为,每次重连都重新从nacos拉取一次服务提供者ip。
fun.ticsmyc.rpc.client.transport.netty.RpcRequestSender 的 42-49 行
该bug表现为: 【只与一个服务器建立了连接, 每次却有若干个心跳包发送】
bootstrap.connect(xxxx).addListener( ()->{
//代码1
this.channel = sync.channel();
}).sync();
//代码2
连接建立之后,代码1和代码2在两个线程中同步执行,无法保证代码1和代码2执行的先后顺序。
在代码1区域为channel赋值的操作可能晚于代码2发生,导致线程同步错误。 应该等到代码1执行完毕后,代码2再执行。
如果代码2先于代码1执行,因为此时channel还未赋值,检测为null,会触发重连操作。 最终系统中会与这一个服务器维持多个连接,导致每次发送多个心跳。
给服务端提供了一个钩子函数,每次下线都注销nacos的信息(但是异常下线的时候仍然会有延迟)。
同时使用以下两个机制实现这个回调
Runtime.getRuntime().addShutdownHook DisposableBean
不知道哪个会生效...
fun.ticsmyc.rpc.common.serializer.impl.JsonSerializer的 90-107行
json是文本序列化器,反序列化时如果不知道原始类型, 可能会导致反序列化失败。
【这种场景下,使用基于二进制的序列化器更好】
fun.ticsmyc.rpc.Config 这个类的static代码块
场景: 想要将服务端配置文件从static改成@Component。 使用properties文件编写配置,使用@Value进行注入。
使用InitializingBean进行赋值。 发现属性还处在配置文件引用阶段("${}"这样),没有替换成配置文件的内容。
@Value获取不到值的场景:
原因: BeanPostProcesser的实例化按照优先级分批进行,优先级高的先于优先级低的进行实例化。 在实例化时,内部依赖的Bean也会实例化。这些被依赖的Bean因为实例化太早,无法享受同等优先级以及更低优先级BeanPostProcesser的处理,所以@Value不会替换。
@Value被AutowiredAnnotationBeanPostProcessor处理,这个BeanPostProcessor也是PriorityOrdered级别的。
详细信息在PriorityOrdered接口的注释中有提到
* <p>Note: {@code PriorityOrdered} post-processor beans are initialized in
* a special phase, ahead of other post-processor beans. This subtly
* affects their autowiring behavior: they will only be autowired against
* beans which do not require eager initialization for type matching.
如果在bean启动的过程中需要通过BeanPostProcessor注册服务,所以必须保证在bean容器初始化的过程之前就读取好了配置文件的内容,所以还是用static比较合适,【但是static乱序初始化也容易造成nullptr】。
每次cas交换AtomicInteger的值, 而不是简单的incrementAndGet(参考了Ribbon)
fun.ticsmyc.rpc.client.proxy.ServiceProxy 的 45-60 行
idea在debug时,会自动对类中属性调用toString,显示在界面上。
如果不做特殊处理,在对客户端的根据rpc服务接口生成的代理类调用toString时,也会触发rpc逻辑,导致发送了一个java.lang.Object_t
的调用请求。 自然就请求错误了。
解决方法: 在动态代理的invoke方法中加入短路逻辑。 如果调用的是Object类的方法或者代理类特有的方法,就本地调用,不执行rpc逻辑。(参考MyBatis)
服务分组(类似dubbo)
增加了针对接口的注解@TRPCInterface
对于什么时候用static 什么时候用单例 还是没有结论。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。