Setting spring.reactor.context-propagation has no effect when lazy initialization is enabled #45853
Setting spring.reactor.context-propagation has no effect when lazy initialization is enabled #45853nosan wants to merge 1 commit into
Conversation
4ba4652 to
9b2aee5
Compare
|
I was initially thinking of the following approach: @AutoConfiguration
@ConditionalOnClass(Hooks.class)
@ConditionalOnProperty(name = "spring.reactor.context-propagation", havingValue = "auto")
@EnableConfigurationProperties(ReactorProperties.class)
public class ReactorAutoConfiguration {
ReactorAutoConfiguration() {
Hooks.enableAutomaticContextPropagation();
}
@Bean
static LazyInitializationExcludeFilter reactorLazyInitializationExcludeFilter() {
return LazyInitializationExcludeFilter.forBeanTypes(ReactorAutoConfiguration.class);
}
}However, As a good alternative, maybe something like this: @AutoConfiguration
@ConditionalOnClass(Hooks.class)
@EnableConfigurationProperties(ReactorProperties.class)
public class ReactorAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.reactor.context-propagation", havingValue = "auto")
static class ReactorContextPropagationConfiguration {
ReactorContextPropagationConfiguration() {
Hooks.enableAutomaticContextPropagation();
}
@Bean
static LazyInitializationExcludeFilter reactorContextPropagationLazyInitExcludeFilter() {
return LazyInitializationExcludeFilter.forBeanTypes(ReactorContextPropagationConfiguration.class);
}
}
} |
|
Arguably, we shouldn't be relying on a side-effect of the constructor being called to configure the hooks and I'd prefer to use a specific callback mechanism instead. For example, implementing Flagging for team attention as I'm not 100% sure that |
|
Thanks, @wilkinsona
@Test
void propagationShouldBeAppliedToSmartInitializingSingletonBeans() {
this.contextRunner.withPropertyValues("spring.reactor.context-propagation=AUTO")
.withInitializer(
(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))
.withBean(VerySmartSingleton.class)
.run((context) -> assertThat(context.getBean(VerySmartSingleton.class).getValue()).isEqualTo("updated"));
}
static class VerySmartSingleton implements SmartInitializingSingleton {
private final AtomicReference<String> threadLocalValue = new AtomicReference<>();
String getValue() {
return this.threadLocalValue.get();
}
@Override
public void afterSingletonsInstantiated() {
Mono.just("test")
.doOnNext((element) -> this.threadLocalValue.set(THREADLOCAL_VALUE.get()))
.contextWrite(Context.of(THREADLOCAL_KEY, "updated"))
.block();
}
} |
|
Indeed. That's why it may not be ideal. There are still ordering concerns with the constructor-based approach as it leaves a window between a bean using Reactor during its standard creation/initialization and |
How about that one? @AutoConfiguration
@ConditionalOnClass(Hooks.class)
@EnableConfigurationProperties(ReactorProperties.class)
public class ReactorAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.reactor.context-propagation", havingValue = "auto")
static class ReactorContextPropagationConfiguration {
@Bean
static BeanFactoryInitializer<ListableBeanFactory> reactorContextPropagationBeanFactoryInitializer() {
return (beanFactory) -> Hooks.enableAutomaticContextPropagation();
}
}
}
|
This commits registers LazyInitializationExcludeFilter to exclude ReactorAutoConfiguration from global lazy init Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
|
No worries, @mhalbritter 😃 |
See #45846