我在Web应用程序中有一些关于Spring Cloud Config的问题 .

Context

我正在开发一个SpringBoot Web应用程序,我有 Root application context (parent)Servlet application context (child) ,我正在为此应用程序添加Spring Cloud Config功能(当然这个应用程序通过http连接到Spring Cloud Config服务器) .

当我使用 RefreshScope 注释注释在Root应用程序上下文中注册的bean时,一切都按预期工作,当我尝试注释在Servlet应用程序上下文中注册的spring bean时,问题就开始了 .

First problem: 当尝试访问servlet应用程序上下文中的 @RefreshScope 注释bean时抛出 IllegalStateException ,以下是stacktrace的有意义部分:

ERROR: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No Scope registered for scope name 'refresh'] with root cause
java.lang.IllegalStateException: No Scope registered for scope name 'refresh'

Solution: 上面的错误是通过将 refresh 范围注册到Servlet应用程序上下文来解决的

@Bean
public CustomScopeConfigurer servletCustomScopeConfigurer(org.springframework.cloud.context.scope.refresh.RefreshScope refreshScope) {
    CustomScopeConfigurer customScopeConfigurer = new CustomScopeConfigurer();
    customScopeConfigurer.addScope("refresh", refreshScope);
    return customScopeConfigurer;
}

Question: 假设这种建模Web应用程序的方式仍然相关(我认为是),为什么我不能将 refresh scope注册到servlet应用程序上下文,我应该从根应用程序上下文中注册 org.springframework.cloud.context.scope.refresh.RefreshScope bean?

Second problem: 一旦我在servlet应用程序上下文中注册了 refresh 作用域,应用程序就可以正常运行了,但是当我尝试从可刷新的bean更新属性时,我已经混合了结果,当我刷新一个可以修改的属性时在根应用程序上下文中的bean我可以看到bean正在更新,所以一切都很好,但是当我更新一个可以修改servlet应用程序上下文中的bean的属性时,我可以设置刷新的bean,但新的属性值不是反映在 beans 子里 .

Solution: 经过一些测试后,我意识到两个上下文中的 ConfigurableEnvironment 都不一样,在某些时候,父 ConfigurableEnvironment 被合并到子 ConfigurableEnvironment ,这就是servlet上下文中的bean在启动时被正确初始化的方式,但当 ContextRefresher.refresh() 被调用时 RefreshEndpoint 只更新了父 ConfigurableEnvironment ,并且子 ConfigurableEnvironment 没有留下旧值,我现在做的是在创建servlet应用程序上下文时注入父 ConfigurableEnvironment 并且一切按预期工作,相关代码:

@Bean
public DispatcherServlet dispatcherServlet(ConfigurableEnvironment parentEnvironment) {
    DispatcherServlet dispatcherServlet = new DispatcherServlet();
    AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
    applicationContext.register(WebConfiguration.class);
    applicationContext.setEnvironment(parentEnvironment);
    dispatcherServlet.setApplicationContext(applicationContext);
    dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
    return dispatcherServlet;
}

Question: 我再次感到惊讶的是缺乏关于Spring应用程序声明父子应用程序上下文的预期行为的文档,也许我只是没有找到它并且它存在并且令人惊讶 . 将父 ConfigurableEnvironment 设置为子servlet上下文的方法是正确的吗?

default 情况下(父级 ConfigurableEnvironment 未在servlet上下文中设置 . )如果是故意的还是bug,那么子 ConfigurableEnvironment 不会刷新的事实?

如果你还在读这个,谢谢!以上问题的答案将非常感谢!

希望这有助于其他人处理这些问题 .