diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/ConfigurableHintsRegistrationProcessor.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/ConfigurableHintsRegistrationProcessor.java index 9dc0f733f..ec3847b59 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/ConfigurableHintsRegistrationProcessor.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/ConfigurableHintsRegistrationProcessor.java @@ -70,7 +70,7 @@ class ConfigurableHintsRegistrationProcessor implements BeanFactoryInitializatio Set.of("org.springframework.security.oauth2.client.OAuth2AuthorizedClient", "org.springframework.security.web.server.SecurityWebFilterChain", "org.springframework.boot.security.autoconfigure.SecurityProperties"), - JsonToGrpcGatewayFilterFactory.class, Set.of("io.grpc.Channel"), RedisRateLimiter.class, + JsonToGrpcGatewayFilterFactory.class, Set.of("io.grpc.netty.NettyChannelBuilder"), RedisRateLimiter.class, Set.of("org.springframework.data.redis.core.RedisTemplate", "org.springframework.web.reactive.DispatcherHandler"), SpringCloudCircuitBreakerResilience4JFilterFactory.class, circuitBreakerConditionalClasses, diff --git a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index b1e2f60fd..f45953ebd 100644 --- a/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server-webflux/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -370,7 +370,7 @@ public GRPCResponseHeadersFilter gRPCResponseHeadersFilter() { @Bean @ConditionalOnEnabledFilter @ConditionalOnProperty(name = "server.http2.enabled", matchIfMissing = true) - @ConditionalOnClass(name = "io.grpc.Channel") + @ConditionalOnClass(name = "io.grpc.netty.NettyChannelBuilder") public JsonToGrpcGatewayFilterFactory jsonToGRPCFilterFactory(GrpcSslConfigurer gRPCSSLContext, ResourceLoader resourceLoader) { return new JsonToGrpcGatewayFilterFactory(gRPCSSLContext, resourceLoader); @@ -379,7 +379,7 @@ public JsonToGrpcGatewayFilterFactory jsonToGRPCFilterFactory(GrpcSslConfigurer @Bean @ConditionalOnEnabledFilter(JsonToGrpcGatewayFilterFactory.class) @ConditionalOnMissingBean(GrpcSslConfigurer.class) - @ConditionalOnClass(name = "io.grpc.Channel") + @ConditionalOnClass(name = "io.grpc.netty.NettyChannelBuilder") public GrpcSslConfigurer grpcSslConfigurer(HttpClientProperties properties, SslBundles bundles) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { TrustManagerFactory trustManagerFactory = TrustManagerFactory diff --git a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java index 095066d68..346b02c80 100644 --- a/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-webflux/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java @@ -57,6 +57,7 @@ import org.springframework.cloud.gateway.actuate.GatewayLegacyControllerEndpoint; import org.springframework.cloud.gateway.config.GatewayAutoConfigurationTests.CustomHttpClientFactory.CustomSslConfigurer; import org.springframework.cloud.gateway.config.HttpClientProperties.Pool.LeasingStrategy; +import org.springframework.cloud.gateway.filter.factory.JsonToGrpcGatewayFilterFactory; import org.springframework.cloud.gateway.filter.factory.TokenRelayGatewayFilterFactory; import org.springframework.cloud.gateway.filter.headers.ForwardedHeadersFilter; import org.springframework.cloud.gateway.filter.headers.GRPCRequestHeadersFilter; @@ -315,6 +316,26 @@ public void gRPCFiltersNotConfiguredWhenHTTP2Disabled() { }); } + @Test // gh-4169 + public void grpcBeansNotConfiguredWhenGrpcNettyAbsent() { + // io.grpc.Channel comes from grpc-api, but the gRPC beans require grpc-netty + // (io.grpc.netty.NettyChannelBuilder). When grpc-api is present without + // grpc-netty the beans must back off rather than fail the context with + // NoClassDefFoundError: io/grpc/netty/NettyChannelBuilder. + new ReactiveWebApplicationContextRunner() + .withClassLoader( + new org.springframework.boot.test.context.FilteredClassLoader("io.grpc.netty.NettyChannelBuilder")) + .withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, MetricsAutoConfiguration.class, + SimpleMetricsExportAutoConfiguration.class, GatewayAutoConfiguration.class, + HttpClientCustomizedConfig.class, ServerPropertiesConfig.class)) + .withPropertyValues("server.http2.enabled=true") + .run(context -> { + assertThat(context).hasNotFailed(); + assertThat(context).doesNotHaveBean(JsonToGrpcGatewayFilterFactory.class); + assertThat(context).doesNotHaveBean(GrpcSslConfigurer.class); + }); + } + @Test public void insecureTrustManagerNotEnabledByDefaultWhenHTTP2Enabled() { new ReactiveWebApplicationContextRunner()