From c4b0aa020abc1267e054fade7ffa01e777667d47 Mon Sep 17 00:00:00 2001 From: onobc Date: Tue, 27 Jan 2026 16:34:08 -0600 Subject: [PATCH 1/2] Add order to client props customizer Sets the `@Order` attribute on the ClientPropertiesChannelBuilderCustomizer which allows users to order their customizers before or after the client props customizer. Also adds order to the de/compressor channel builder customizers. Fixes #359 Signed-off-by: onobc --- .../GrpcClientAutoConfiguration.java | 24 ++++++++++++ .../GrpcClientAutoConfigurationTests.java | 37 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java b/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java index 6203824e..75562d36 100644 --- a/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java +++ b/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java @@ -28,6 +28,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; import org.springframework.grpc.client.ChannelCredentialsProvider; import org.springframework.grpc.client.ClientInterceptorsConfigurer; import org.springframework.grpc.client.CoroutineStubFactory; @@ -46,6 +47,26 @@ GrpcChannelFactoryConfigurations.InProcessChannelFactoryConfiguration.class, ClientScanConfiguration.class }) public final class GrpcClientAutoConfiguration { + /** + * Order applied to the {@link ClientPropertiesChannelBuilderCustomizer} used to apply + * {@link GrpcClientProperties} to channel builders. + */ + public static final int CLIENT_PROPS_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 0; + + /** + * Order applied to the {@link GrpcChannelBuilderCustomizer + * compressionClientCustomizer} used to set the compressor registry on the channel + * builder. + */ + public static final int COMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 1; + + /** + * Order applied to the {@link GrpcChannelBuilderCustomizer + * decompressionClientCustomizer} used to set the decompressor registry on the channel + * builder. + */ + public static final int DECOMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 2; + @Bean @ConditionalOnMissingBean ClientInterceptorsConfigurer clientInterceptorsConfigurer(ApplicationContext applicationContext) { @@ -59,6 +80,7 @@ NamedChannelCredentialsProvider channelCredentialsProvider(SslBundles bundles, G } @Bean + @Order(CLIENT_PROPS_CHANNEL_BUILDER_CUSTOMIZER_ORDER) > GrpcChannelBuilderCustomizer clientPropertiesChannelCustomizer( GrpcClientProperties properties) { return new ClientPropertiesChannelBuilderCustomizer<>(properties); @@ -66,6 +88,7 @@ > GrpcChannelBuilderCustomizer clientPrope @ConditionalOnBean(CompressorRegistry.class) @Bean + @Order(COMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER) > GrpcChannelBuilderCustomizer compressionClientCustomizer( CompressorRegistry registry) { return (name, builder) -> builder.compressorRegistry(registry); @@ -73,6 +96,7 @@ > GrpcChannelBuilderCustomizer compression @ConditionalOnBean(DecompressorRegistry.class) @Bean + @Order(DECOMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER) > GrpcChannelBuilderCustomizer decompressionClientCustomizer( DecompressorRegistry registry) { return (name, builder) -> builder.decompressorRegistry(registry); diff --git a/spring-grpc-client-spring-boot-autoconfigure/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java b/spring-grpc-client-spring-boot-autoconfigure/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java index 3b2daf93..0cd1c20f 100644 --- a/spring-grpc-client-spring-boot-autoconfigure/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java +++ b/spring-grpc-client-spring-boot-autoconfigure/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java @@ -48,6 +48,7 @@ import org.springframework.grpc.client.InProcessGrpcChannelFactory; import org.springframework.grpc.client.NettyGrpcChannelFactory; import org.springframework.grpc.client.ShadedNettyGrpcChannelFactory; +import org.springframework.test.util.ReflectionTestUtils; import io.grpc.Codec; import io.grpc.CompressorRegistry; @@ -230,6 +231,21 @@ void channelBuilderCustomizersAutoConfiguredAsExpected() { ChannelBuilderCustomizersConfig.CUSTOMIZER_FOO)); } + @Test + void userDefinedCustomizerCanRunBeforeAndAfterClientPropsCustomizer() { + this.contextRunner().withUserConfiguration(UserClientPropsCustomizerConfig.class).run((context) -> { + // NOTE: AssertJ "extract list + satisfies" balks about generic types + // so we have to do this the old fashion way. + var clientPropsCustomizer = context.getBean(ClientPropertiesChannelBuilderCustomizer.class); + var channelBuilderCustomizers = context.getBean(ChannelBuilderCustomizers.class); + List> customizers = (List>) ReflectionTestUtils + .getField(channelBuilderCustomizers, "customizers"); + assertThat(customizers).isNotNull(); + assertThat(customizers).containsSequence(UserClientPropsCustomizerConfig.CUSTOMIZER_PRE_CLIENT_PROPS, + clientPropsCustomizer, UserClientPropsCustomizerConfig.CUSTOMIZER_POST_CLIENT_PROPS); + }); + } + @Test void clientScanConfigurationAutoConfiguredAsExpected() { this.contextRunner().run((context) -> assertThat(context).hasSingleBean(ClientScanConfiguration.class)); @@ -447,4 +463,25 @@ GrpcChannelBuilderCustomizer customizerBar() { } + @Configuration(proxyBeanMethods = false) + static class UserClientPropsCustomizerConfig { + + static GrpcChannelBuilderCustomizer CUSTOMIZER_PRE_CLIENT_PROPS = mock(); + + static GrpcChannelBuilderCustomizer CUSTOMIZER_POST_CLIENT_PROPS = mock(); + + @Bean + @Order(GrpcClientAutoConfiguration.CLIENT_PROPS_CHANNEL_BUILDER_CUSTOMIZER_ORDER - 1) + GrpcChannelBuilderCustomizer customizerFoo() { + return CUSTOMIZER_PRE_CLIENT_PROPS; + } + + @Bean + @Order(GrpcClientAutoConfiguration.CLIENT_PROPS_CHANNEL_BUILDER_CUSTOMIZER_ORDER + 1) + GrpcChannelBuilderCustomizer customizerBar() { + return CUSTOMIZER_POST_CLIENT_PROPS; + } + + } + } From 97cbaeb0644a8acfe705b7d143cdaab6f6074e8b Mon Sep 17 00:00:00 2001 From: onobc Date: Tue, 27 Jan 2026 16:45:41 -0600 Subject: [PATCH 2/2] Give space between customizer ordering Changes the compressor and decompressor customizer order attributes from `1` and `2` to `5` and `10` to give some breathing room in case users need to order before or after either of them. See #359 Signed-off-by: onobc (cherry picked from commit d44e4de3e2b6e103c448120f70280ecfd09e80a4) --- .../client/autoconfigure/GrpcClientAutoConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java b/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java index 75562d36..c5ff715b 100644 --- a/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java +++ b/spring-grpc-client-spring-boot-autoconfigure/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java @@ -58,14 +58,14 @@ public final class GrpcClientAutoConfiguration { * compressionClientCustomizer} used to set the compressor registry on the channel * builder. */ - public static final int COMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 1; + public static final int COMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 5; /** * Order applied to the {@link GrpcChannelBuilderCustomizer * decompressionClientCustomizer} used to set the decompressor registry on the channel * builder. */ - public static final int DECOMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 2; + public static final int DECOMPRESSION_CHANNEL_BUILDER_CUSTOMIZER_ORDER = 10; @Bean @ConditionalOnMissingBean