Closed DeBruyne2020 closed 1 year ago
这个问题我们在2021.x分支上做了部分优化的,具体可以见#2437,可以做到只刷新特定改动的配置,但是还不支持你说的不重启spring上下文。这块有兴趣可以一起来建设哈:)
这个问题我们在2021.x分支上做了部分优化的,具体可以见#2437,可以做到只刷新特定改动的配置,但是还不支持你说的不重启spring上下文。这块有兴趣可以一起来建设哈:)
好的,谢谢大佬,
这块很有兴趣, 请问大佬我可以在您说的这个2021.x分支上或者另外的分支上做代码提交以此来优化改进这个问题吗?或者可以先商量讨论下改动方法改动思路什么的?
这个问题我们在2021.x分支上做了部分优化的,具体可以见#2437,可以做到只刷新特定改动的配置,但是还不支持你说的不重启spring上下文。这块有兴趣可以一起来建设哈:)
好的,谢谢大佬, 这块很有兴趣, 请问大佬我可以在您说的这个2021.x分支上或者另外的分支上做代码提交以此来优化改进这个问题吗?或者可以先商量讨论下改动方法改动思路什么的?
嗯嗯,是的,在2021.x分支上改动就好了,可以先在这个issues下面留言说一下你这边详细的方案思路,我们可以一起看一下。
这个问题我们在2021.x分支上做了部分优化的,具体可以见#2437,可以做到只刷新特定改动的配置,但是还不支持你说的不重启spring上下文。这块有兴趣可以一起来建设哈:)
好的,谢谢大佬, 这块很有兴趣, 请问大佬我可以在您说的这个2021.x分支上或者另外的分支上做代码提交以此来优化改进这个问题吗?或者可以先商量讨论下改动方法改动思路什么的?
嗯嗯,是的,在2021.x分支上改动就好了,可以先在这个issues下面留言说一下你这边详细的方案思路,我们可以一起看一下。
好的 👌 , 谢谢大佬
@RefreshScope
动态刷新并不是一种优雅的做法,推荐封装成类使用 @ConfigurationProperties
完成动态刷新功能。
- 使用
@RefreshScope
动态刷新并不是一种优雅的做法,推荐封装成类使用@ConfigurationProperties
完成动态刷新功能。- 采用反射对于基本的数据结构是可取的,但是如果是复杂类型数据结构会带来较大的解析成本,降低稳定性。
@DanielLiu1123 大佬好~,如果用@ConfigurationProperties去刷新配置,那有办法做到不重启spring上下文么?
它那个refreshEvent里头那个refresh处理是很慢的,打个断点卡老半天
这个问题我们在2021.x分支上做了部分优化的,具体可以见#2437,可以做到只刷新特定改动的配置,但是还不支持你说的不重启spring上下文。这块有兴趣可以一起来建设哈:)
好的,谢谢大佬, 这块很有兴趣, 请问大佬我可以在您说的这个2021.x分支上或者另外的分支上做代码提交以此来优化改进这个问题吗?或者可以先商量讨论下改动方法改动思路什么的?
嗯嗯,是的,在2021.x分支上改动就好了,可以先在这个issues下面留言说一下你这边详细的方案思路,我们可以一起看一下。
@steverao @DanielLiu1123 大佬好,我有两个改动思路如下: 思路1:
step 1 定义一个注解@RefreshValue ,加在包含有想能够动态刷新的配置的类的类头上
step2 定义一个类implements BeanPostProcessor, ApplicationListener
思路2: 和思路1的区别就是无需自定义注解,就是在spring启动的时候找到所有含有配置值(如@Value注解)的类,写到一个map里,key是属性key,value是类,在com.alibaba.cloud.nacos.refresh.NacosContextRefresher的registerNacosListener方法里 ,把applicationContext.publishEvent(new RefreshEvent(this, null, "Refresh Nacos config")); 去掉(这样就不重启spring上下文了),然后通过上面的map就找到对应的类及具体的属性,正常通过反射去set赋值就可以了
上面两种思路,其中思路1已经写好代码,并且试验是成功的,spring上下文不重启,配置值也实时刷新了
大佬看上面的方案思路可以吗?大佬觉得哪种思路更好? 方案思路可以的话我就提交代码了
欢迎提交 PR ~
这里有一个很致命的问题,如果不发送 RefreshEvent
事件,那么很多依赖于该事件的功能都将不起作用,这是一个 breaking change
这里有一个很致命的问题,如果不发送
RefreshEvent
事件,那么很多依赖于该事件的功能都将不起作用,这是一个 breaking change
@DanielLiu1123 “那么很多依赖于该事件的功能都将不起作用”,大佬能举个例子么, 比如具体一个什么样的功能?我没有完全get到,现在是只是改了nacos的配置值,那么最终目的不是让用到nacos配置值的地方刷新成最新的值就可以么?,“依赖于该事件的功能” 是指有哪些?
然后第二个问题是如果发送RefreshEvent事件,有什么办法能spring上下文不重启吗?
@steverao @DanielLiu1123 大佬 问下哈 , springcloudalibaba有微信群QQ群钉钉群之类的么?
@steverao @DanielLiu1123 大佬 问下哈 , springcloudalibaba有微信群QQ群钉钉群之类的么?
钉钉群:34351718
@steverao @DanielLiu1123 大佬 问下哈 , springcloudalibaba有微信群QQ群钉钉群之类的么?
钉钉群:34351718
感谢大佬
这里有一个很致命的问题,如果不发送
RefreshEvent
事件,那么很多依赖于该事件的功能都将不起作用,这是一个 breaking change@DanielLiu1123 “那么很多依赖于该事件的功能都将不起作用”,大佬能举个例子么, 比如具体一个什么样的功能?我没有完全get到,现在是只是改了nacos的配置值,那么最终目的不是让用到nacos配置值的地方刷新成最新的值就可以么?,“依赖于该事件的功能” 是指有哪些?
然后第二个问题是如果发送RefreshEvent事件,有什么办法能spring上下文不重启吗?
CircuitBreakerRuleChangeListener
, Gateway RouteRefreshListener
都会间接依赖于该事件,如果不触发 RefreshEvent
,这些功能都会失效,存在极高的风险(配置在 Nacos 的路由,熔断配置都不会刷新)。org.springframework.cloud.context.refresh.ContextRefresher
这里有一个很致命的问题,如果不发送
RefreshEvent
事件,那么很多依赖于该事件的功能都将不起作用,这是一个 breaking change@DanielLiu1123 “那么很多依赖于该事件的功能都将不起作用”,大佬能举个例子么, 比如具体一个什么样的功能?我没有完全get到,现在是只是改了nacos的配置值,那么最终目的不是让用到nacos配置值的地方刷新成最新的值就可以么?,“依赖于该事件的功能” 是指有哪些? 然后第二个问题是如果发送RefreshEvent事件,有什么办法能spring上下文不重启吗?
- Sentinel
CircuitBreakerRuleChangeListener
, GatewayRouteRefreshListener
都会间接依赖于该事件,如果不触发RefreshEvent
,这些功能都会失效,存在极高的风险(配置在 Nacos 的路由,熔断配置都不会刷新)。- 在 Spring Boot 2.4 以前会启动一个无头服务来刷新环境,确实成本比较高;但是 Spring Boot 2.4 以后采取了更轻量的实现方式。see
org.springframework.cloud.context.refresh.ContextRefresher
@DanielLiu1123 收到,感谢大佬的指点🙏,感谢!
我现在正在看spring源码,还不确定您说的springBoot2.4之后采取更轻量的实现是具体有多轻量,不知是否可以做到服务在eureka注册中心上不重启?
另外还有下面一个思路您看看如何:定义一个环境变量“SpringCloudAlibabaNacosMode”,在com.alibaba.cloud.nacos.refresh.NacosContextRefresher#registerNacosListener方法里识别下这个环境变量,默认都走您说的publishEvent RefreshEvent , 只有当这个环境变量配成指定值时,才不走publishEvent RefreshEvent,走单独用反射去更改属性值的代码逻辑分支。 这样做的目的是保证默认都走发送RefreshEvent事件,保证您说的诸如Sentinel CircuitBreakerRuleChangeListener
, Gateway `RouteRefreshListener这样的功能不受影响,但是当服务没有用到这些功能,服务用nacos配置都只是在业务代码里做业务配置用的时候, 则可以给使用者一个选择渠道,选择切到不触发RefreshEvent事件,用最轻量的反射更改属性值的方式, 您看这个思路如何~?
可以结合nacos和apollo的优势,使用Apollo的方式管理@value注解,使用事件机制管理@ConfigurationProperties,但是不用RefreshEvent事件,这会引起通过新建spring容器使RefreshScope的bean重建,代价比较大,可以使用EnvironmentChangeEvent 事件触发只重新绑定properties就行了。有个比较完善并且可实际使用的例子,并且完美支持配置加解密:https://github.com/fuxiuzhan/fuled-component/tree/master/fuled-config-starter
其实nacos本身是依赖RefreshEvent事件来完成配置的更新的,nacos-config每次有RefreshEvent触发时要把所有配置全部请求一遍,把新的配置加到spring的environment 中。如果不触发RefreshEvent事件,nacos只能知道变更了什么东西,但无法把变更加到environment中,变量重新绑定拿到的依然是旧值。每次变更全量请求这块代价也是比较大的。在上边提到的项目中做到了变更了那个值就精确的更新那个值,然后只刷新对应的@value和properties,更快速且代价非常小。
其实这个项目是可以支持局部刷新的,不知道为啥没引入 nacos-spring-project issue bilibili介绍 4年前就没听明白,现在也还是不明白。。。
目的可能是这样:
RefreshEvent
是以SpringCloud的方式来刷新应用配置其实这个项目是可以支持局部刷新的,不知道为啥没引入 nacos-spring-project issue bilibili介绍 4年前就没听明白,现在也还是不明白。。。
目的可能是这样:
RefreshEvent
是以SpringCloud的方式来刷新应用配置- nacos-spring-project 单独刷新字段或者Bean配置 在项目中同时引入,各取所需。
利用 nacos-spring-project 实现了一下 https://github.com/liqi19950722/demo/
SCA is not suitable for implementing this feature, bring uncertain risk.
其实这个项目是可以支持局部刷新的,不知道为啥没引入 nacos-spring-project issue bilibili介绍 4年前就没听明白,现在也还是不明白。。。 目的可能是这样:
RefreshEvent
是以SpringCloud的方式来刷新应用配置- nacos-spring-project 单独刷新字段或者Bean配置 在项目中同时引入,各取所需。
利用 nacos-spring-project 实现了一下 https://github.com/liqi19950722/demo/
L47 clear method is not safe.
问下各位大佬, nacos现在动态发布配置的机制是依赖spring的RefreshScope注解,RefreshScope注解配在配置所在的类头上,类似于这样:
服务在线的情况下,发布这个配置,这会导致spring上下文重新加载,导致服务重启,表现为在注册中心(如eureka)上先down一下然后再up(虽然这个过程可能非常快),,为什么nacos不采用类似apollo的动态发布方式,也就是通过beanFactory找到对应的配置所在的类,然后用反射的方式修改具体配置的值,这样整个spring上下文是不重启的,服务不会重启。
这个说是springcloud/springcloudalibaba的标准导致目前的这个现状,所以在这里问问