Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于SpringCloud的bootstrap阶段PropertySources的建议 #3610

Open
magooup opened this issue Mar 22, 2021 · 7 comments
Open

关于SpringCloud的bootstrap阶段PropertySources的建议 #3610

magooup opened this issue Mar 22, 2021 · 7 comments
Labels
area/client apollo-client area/sdk Categorizes issue or PR as related to client sdk discussion Categorizes issue as related to discussion feature request Categorizes issue as related to a new feature.

Comments

@magooup
Copy link

magooup commented Mar 22, 2021

你的特性请求和某个问题有关吗?请描述

  • SpringCloud项目一般会将父上下文bootstrap阶段相关的配置约定在本地bootstrap.yml/properties文件中(例如spring.application.name、远程配置地址/开关等),而将远程配置PropertySource放置在子上下文环境中。我认同这种机制能很好的隔离用户和环境配置,用户在远程的配置不会影响到某些预设配置(如服务ID、注册中心地址等)。
  • 而Apollo在启用eagerLoad之后,无论什么阶段都会将ApolloPropertySources前置,在SpringCloud项目中会打破上述机制。即使在bootstrap阶段,spring.application.name等配置值仍会优先从Apollo远程配置中获取,极易因用户的不当配置引发预期之外的问题,如调用链路中断(spring.application.name常被用于各种组件的唯一标识,如eureka服务的appId;这种是应当在项目建立时就固定的约定)。
  • SpringCloud config方式和Apollo方式propertySources的区别见末尾。

清晰简洁地描述一下你希望的解决方案

  • 希望与SpringCloud项目集成时可以遵循远程配置约定。在bootstrap环境中不加载ApolloPropertySources或者使用推荐的扩展方式引入ApolloPropertySources (在spring.factories中扩展org.springframework.cloud.bootstrap.BootstrapConfiguration)。

清晰简洁地描述一下这个特性的备选方案

  • 我当前的处理方式是在自定义的EnvironmentPostProcessor中通过提前占位的方式阻止bootstrap阶段的ApolloBootstrapPropertySources添加。如图所示:

my-process

其它背景

  • Apollo SpringCloud父子阶段的propertySources:

test-apollo-1

test-apollo-2

  • SpringCloud config父子阶段的propertySources:

test-cloud-1

test-cloud-2

@nobodyiam nobodyiam added area/client apollo-client area/sdk Categorizes issue or PR as related to client sdk discussion Categorizes issue as related to discussion labels Mar 24, 2021
@nobodyiam
Copy link
Member

主要的问题是担心 spring.application.name/server.port 这些值被远端配置覆盖掉?
这个是否还是取决于用户的实际使用情况?一般情况用户不会配置,如果配置的话,是否要看下用户的意图是希望 apollo 的生效还是代码中的生效?

@magooup
Copy link
Author

magooup commented Mar 29, 2021

主要的问题是担心 spring.application.name/server.port 这些值被远端配置覆盖掉?
这个是否还是取决于用户的实际使用情况?一般情况用户不会配置,如果配置的话,是否要看下用户的意图是希望 apollo 的生效还是代码中的生效?

@nobodyiam 是这个意思。

我觉得大多数场景用户应该不会有这种自由意图,在项目立项之初,应用名/应用端口应当属于被指定且被约束的,因为这些配置往往会被其他组件/其他系统引用,比如nginx upstream的映射,无注册中心的服务调用等。

结合SpringCloud配置的做法,我猜测它也希望在bootstrap阶段,内置组件初始化注入所需的配置不被扩展配置影响。在重启(故障或手动)动作之后,应用程序启动主流程的行为应当保持一致。

虽然可以通过账户权限限制或者操作行为规范引导用户不做这种配置,但是真的很难保障一定不会出现误操作的情况。比如修改了应用名或端口,一旦此时重启程序,可能会造成一连串的不可预知的内部和外部关联错误。

非Spring项目或者SpringBoot项目不存在这个问题,但是在SpringCloud项目我比较在意这种不可控因素,还是挺希望能与SpringCloud自身的扩展配置机制有一致的行为。不知道是否考虑spring-cloud-config-apollo这样的特定扩展?

@nobodyiam
Copy link
Member

SpringBoot项目不存在这个问题

Spring Boot 项目为啥不存在这个问题?spring.application.name/server.port 这些值也是可以配置的

@magooup
Copy link
Author

magooup commented Apr 1, 2021

SpringBoot项目不存在这个问题

Spring Boot 项目为啥不存在这个问题?spring.application.name/server.port 这些值也是可以配置的

抱歉,描述不准确。应当是“不存在这个争议”,spring-boot默认只有一个environment,对PropertySource的扩展各家自由度较高(我司common-config扩展了一个优先级更高的constraint.yml(or properties)用于约束固定不可变配置)。

而spring-cloud多了一个bootstrap引导阶段,BootstrapApplicationListener的doc中这样描述:

A listener that prepares a SpringApplication (e.g. populating its Environment) by delegating to ApplicationContextInitializer beans in a separate bootstrap context. The bootstrap context is a SpringApplication created from sources defined in spring.factories as BootstrapConfiguration, and initialized with external config taken from "bootstrap.properties" (or yml), instead of the normal "application.properties".

上述我理解为spring-cloud希望只从bootstrap.properties|yml中读取引导配置,用于初始化spring.factories中指定的BootstrapConfiguration 扩展的beans,包含:discovery/cloud-config。对于远程配置中心,在bootstrap.properties配置远程git仓库地址(spring-cloud-config)、nacos server地址(spring-cloud-alibaba-nacos-config),而spring.application.name用于指定git仓库中的子目录(spring-cloud-config)、nacos dataId的组成部分(spring-cloud-alibaba-nacos-config)。对上述远程配置中心,父的bootstrapContext只做了prepare工作,直到子context时才将对应的PropertySource加入。

我司common-config定制之后,对Apollo的使用与上述相同,在bootstrap中只指定meta server地址,用spring.application.name作为优先的namespace,在子context中才将ApolloPropertySources放入envionment,我认为这种方式与spring-cloud-configspring-cloud-alibaba-nacos-config一致,也符合spring-cloud引导阶段的意图。因此才提出希望作者考虑可以在与spring-cloud结合时原生支持上述场景。(方便的做法可以考虑抽离一个单独的项目spring-cloud-config-apollo,扩展BootstrapConfiguration。)

描述不正确的地方请指正。

@nobodyiam
Copy link
Member

感谢详细的说明,单独抽离一个项目spring-cloud-config-apollo的话,是指用户引入这个项目后,就不配置apollo.bootstrap.xxx等配置,而改为直接启用 spring cloud config apollo 的配置?
另外,spring cloud 2020.0 开始已经默认禁用 bootstrap了,这块是否会有啥影响?

@magooup
Copy link
Author

magooup commented Apr 6, 2021

单独抽离一个项目spring-cloud-config-apollo的话,是指用户引入这个项目后,就不配置apollo.bootstrap.xxx等配置,而改为直接启用 spring cloud config apollo 的配置

是的,是这个效果。

另外,spring cloud 2020.0 开始已经默认禁用 bootstrap了,这块是否会有啥影响?

不好意思之前也没细看2020版本的变化。查了一下,从2020开始SpringCloud默认不再使用bootstrapContext引导启动了,加载configserver只需要这样:spring.config.import=optional:configserver:http://localhost:9000
如果采用spring-cloud-config-apollo这种方式的话,就要跟随SpringCloud版本的变化而变化了。对于2020.0.x这个版本,要么使用legacy bootstrap兼容方式,要么适配它新的配置中心加载方式(具体我还没看源码😅)。

@nobodyiam nobodyiam added the feature request Categorizes issue as related to a new feature. label Apr 10, 2021
@nobodyiam
Copy link
Member

看了一下相关的源码,单独建一个 spring-cloud-config-apollo 应该也是可行的,不过目前看除了支持BootstrapConfiguration配置外,其它似乎没有看到特别有价值的点?如果要让用户采用一个新的 sdk 的话,可能还需要补充更多的场景进来~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/client apollo-client area/sdk Categorizes issue or PR as related to client sdk discussion Categorizes issue as related to discussion feature request Categorizes issue as related to a new feature.
Projects
None yet
Development

No branches or pull requests

2 participants