Move some components into core module

This commit moves several components into the core module
from the autoconfiguration module. Anything that exists
in the AC module will ultimately end up in Spring Boot
project assuming we move into Spring Boot in the future.

Signed-off-by: Chris Bono <chris.bono@gmail.com>
This commit is contained in:
Chris Bono
2024-11-14 11:33:44 -06:00
committed by Dave Syer
parent d629f9f547
commit e3d58cf988
18 changed files with 129 additions and 125 deletions

View File

@@ -70,13 +70,9 @@
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -22,10 +22,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import io.grpc.ServerInterceptor;
import org.springframework.core.annotation.Order;
import io.grpc.ServerInterceptor;
/**
* Annotation that can be specified on a gRPC {@link ServerInterceptor} bean which will
* result in the interceptor being applied globally to all services.

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import java.lang.annotation.Annotation;
import java.util.LinkedHashMap;

View File

@@ -13,20 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.grpc.server.GlobalServerInterceptor;
import org.springframework.lang.Nullable;
import io.grpc.BindableService;
import io.grpc.ServerInterceptor;
import io.grpc.ServerInterceptors;
import io.grpc.ServerServiceDefinition;
import jakarta.annotation.PostConstruct;
/**
* Default {@link GrpcServiceConfigurer} that binds and configures services with
@@ -34,7 +35,7 @@ import jakarta.annotation.PostConstruct;
*
* @author Chris Bono
*/
public class DefaultGrpcServiceConfigurer implements GrpcServiceConfigurer {
public class DefaultGrpcServiceConfigurer implements GrpcServiceConfigurer, InitializingBean {
private final ApplicationContext applicationContext;
@@ -44,8 +45,8 @@ public class DefaultGrpcServiceConfigurer implements GrpcServiceConfigurer {
this.applicationContext = applicationContext;
}
@PostConstruct
private void initializeGlobalInterceptors() {
@Override
public void afterPropertiesSet() {
this.globalInterceptors = findGlobalInterceptors();
}

View File

@@ -14,12 +14,11 @@
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.grpc.server.GrpcServiceDiscoverer;
import org.springframework.lang.Nullable;
import io.grpc.BindableService;

View File

@@ -16,7 +16,7 @@
* Copy from net.devh:grpc-spring-boot-starter.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import org.springframework.lang.Nullable;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.grpc.server;
package org.springframework.grpc.server.service;
import java.util.List;

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import java.util.List;

View File

@@ -14,18 +14,16 @@
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.function.Function;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
@@ -38,9 +36,11 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.grpc.server.GlobalServerInterceptor;
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
import org.springframework.lang.Nullable;
@@ -58,8 +58,7 @@ class DefaultGrpcServiceConfigurerTests {
private ApplicationContextRunner contextRunner() {
// NOTE: we use noop server lifecycle to avoid startup
return new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(GrpcServerAutoConfiguration.class))
return new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(ServiceConfigurerConfig.class))
.withBean("noopServerLifecycle", GrpcServerLifecycle.class, Mockito::mock);
}
@@ -67,12 +66,62 @@ class DefaultGrpcServiceConfigurerTests {
void globalServerInterceptorsAreFoundInProperOrder() {
this.contextRunner()
.withUserConfiguration(GlobalServerInterceptorsConfig.class)
.run((context) -> assertThat(context).getBean(DefaultGrpcServiceConfigurer.class)
.run((context) -> Assertions.assertThat(context)
.getBean(DefaultGrpcServiceConfigurer.class)
.extracting("globalInterceptors", InstanceOfAssertFactories.LIST)
.containsExactly(GlobalServerInterceptorsConfig.GLOBAL_INTERCEPTOR_BAR,
GlobalServerInterceptorsConfig.GLOBAL_INTERCEPTOR_FOO));
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
List<ServerInterceptor> expectedInterceptors) {
this.customizeContextAndRunServiceConfigurerWithServiceInfo(contextCustomizer, serviceInfo,
expectedInterceptors, null);
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
Class<? extends Throwable> expectedExceptionType) {
this.customizeContextAndRunServiceConfigurerWithServiceInfo(contextCustomizer, serviceInfo, null,
expectedExceptionType);
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
@Nullable List<ServerInterceptor> expectedInterceptors,
@Nullable Class<? extends Throwable> expectedExceptionType) {
// It gets difficult to verify interceptors are added properly to mocked services.
// To make it easier, we just static mock ServerInterceptors.interceptForward to
// echo back the service def. This way we can verify the interceptors were passed
// in the proper order as we rely on ServerInterceptors.interceptForward being
// well tested in grpc-java.
try (MockedStatic<ServerInterceptors> serverInterceptorsMocked = Mockito.mockStatic(ServerInterceptors.class)) {
serverInterceptorsMocked
.when(() -> ServerInterceptors.interceptForward(any(ServerServiceDefinition.class), anyList()))
.thenAnswer((Answer<ServerServiceDefinition>) invocation -> invocation.getArgument(0));
BindableService service = Mockito.mock();
ServerServiceDefinition serviceDef = Mockito.mock();
Mockito.when(service.bindService()).thenReturn(serviceDef);
this.contextRunner()
.withBean("service", BindableService.class, () -> service)
.with(contextCustomizer)
.run((context) -> {
DefaultGrpcServiceConfigurer configurer = context.getBean(DefaultGrpcServiceConfigurer.class);
if (expectedExceptionType != null) {
assertThatThrownBy(() -> configurer.configure(service, serviceInfo))
.isInstanceOf(expectedExceptionType);
serverInterceptorsMocked.verifyNoInteractions();
}
else {
configurer.configure(service, serviceInfo);
serverInterceptorsMocked
.verify(() -> ServerInterceptors.interceptForward(serviceDef, expectedInterceptors));
}
});
}
}
@Nested
class WithNoServiceInfoSpecified {
@@ -224,55 +273,6 @@ class DefaultGrpcServiceConfigurerTests {
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
List<ServerInterceptor> expectedInterceptors) {
this.customizeContextAndRunServiceConfigurerWithServiceInfo(contextCustomizer, serviceInfo,
expectedInterceptors, null);
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
Class<? extends Throwable> expectedExceptionType) {
this.customizeContextAndRunServiceConfigurerWithServiceInfo(contextCustomizer, serviceInfo, null,
expectedExceptionType);
}
private void customizeContextAndRunServiceConfigurerWithServiceInfo(
Function<ApplicationContextRunner, ApplicationContextRunner> contextCustomizer, GrpcServiceInfo serviceInfo,
@Nullable List<ServerInterceptor> expectedInterceptors,
@Nullable Class<? extends Throwable> expectedExceptionType) {
// It gets difficult to verify interceptors are added properly to mocked services.
// To make it easier, we just static mock ServerInterceptors.interceptForward to
// echo back the service def. This way we can verify the interceptors were passed
// in the proper order as we rely on ServerInterceptors.interceptForward being
// well tested in grpc-java.
try (MockedStatic<ServerInterceptors> serverInterceptorsMocked = Mockito.mockStatic(ServerInterceptors.class)) {
serverInterceptorsMocked
.when(() -> ServerInterceptors.interceptForward(any(ServerServiceDefinition.class), anyList()))
.thenAnswer((Answer<ServerServiceDefinition>) invocation -> invocation.getArgument(0));
BindableService service = mock();
ServerServiceDefinition serviceDef = mock();
when(service.bindService()).thenReturn(serviceDef);
this.contextRunner()
.withBean("service", BindableService.class, () -> service)
.with(contextCustomizer)
.run((context) -> {
DefaultGrpcServiceConfigurer configurer = context.getBean(DefaultGrpcServiceConfigurer.class);
if (expectedExceptionType != null) {
assertThatThrownBy(() -> configurer.configure(service, serviceInfo))
.isInstanceOf(expectedExceptionType);
serverInterceptorsMocked.verifyNoInteractions();
}
else {
configurer.configure(service, serviceInfo);
serverInterceptorsMocked
.verify(() -> ServerInterceptors.interceptForward(serviceDef, expectedInterceptors));
}
});
}
}
interface TestServerInterceptorA extends ServerInterceptor {
}
@@ -282,24 +282,24 @@ class DefaultGrpcServiceConfigurerTests {
}
@Configuration(proxyBeanMethods = false)
static class GlobalServerInterceptorsConfig {
static BindableService SERVICE_A = mock();
static ServerServiceDefinition SERVICE_DEF_A = mock();
static ServerInterceptor GLOBAL_INTERCEPTOR_FOO = mock();
static ServerInterceptor GLOBAL_INTERCEPTOR_IGNORED = mock();
static ServerInterceptor GLOBAL_INTERCEPTOR_BAR = mock();
static class ServiceConfigurerConfig {
@Bean
BindableService serviceA() {
when(SERVICE_A.bindService()).thenReturn(SERVICE_DEF_A);
return SERVICE_A;
GrpcServiceConfigurer grpcServiceConfigurer(ApplicationContext applicationContext) {
return new DefaultGrpcServiceConfigurer(applicationContext);
}
}
@Configuration(proxyBeanMethods = false)
static class GlobalServerInterceptorsConfig {
static ServerInterceptor GLOBAL_INTERCEPTOR_FOO = Mockito.mock();
static ServerInterceptor GLOBAL_INTERCEPTOR_IGNORED = Mockito.mock();
static ServerInterceptor GLOBAL_INTERCEPTOR_BAR = Mockito.mock();
@Bean
@Order(200)
@GlobalServerInterceptor
@@ -325,9 +325,9 @@ class DefaultGrpcServiceConfigurerTests {
@Configuration(proxyBeanMethods = false)
static class ServiceSpecificInterceptorsConfig {
static TestServerInterceptorB SVC_INTERCEPTOR_B = mock();
static TestServerInterceptorB SVC_INTERCEPTOR_B = Mockito.mock();
static TestServerInterceptorA SVC_INTERCEPTOR_A = mock();
static TestServerInterceptorA SVC_INTERCEPTOR_A = Mockito.mock();
@Bean
@Order(150)

View File

@@ -14,13 +14,11 @@
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.grpc.autoconfigure.server.DefaultGrpcServiceDiscovererTests.DefaultGrpcServiceDiscovererTestsConfig.SERVICE_A;
import static org.springframework.grpc.autoconfigure.server.DefaultGrpcServiceDiscovererTests.DefaultGrpcServiceDiscovererTestsConfig.SERVICE_B;
import static org.springframework.grpc.server.service.DefaultGrpcServiceDiscovererTests.DefaultGrpcServiceDiscovererTestsConfig.SERVICE_A;
import static org.springframework.grpc.server.service.DefaultGrpcServiceDiscovererTests.DefaultGrpcServiceDiscovererTestsConfig.SERVICE_B;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -29,12 +27,11 @@ import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
import io.grpc.BindableService;
import io.grpc.ServerServiceDefinition;
@@ -46,24 +43,15 @@ import io.grpc.ServerServiceDefinition;
*/
class DefaultGrpcServiceDiscovererTests {
private ApplicationContextRunner contextRunner() {
// NOTE: we use noop server lifecycle to avoid startup
return new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(GrpcServerAutoConfiguration.class))
.withBean("noopServerLifecycle", GrpcServerLifecycle.class, Mockito::mock);
}
@Test
void servicesAreFoundInProperOrderWithExpectedGrpcServiceAnnotations() {
TestServiceConfigurer configurer = new TestServiceConfigurer();
this.contextRunner()
.withUserConfiguration(DefaultGrpcServiceDiscovererTestsConfig.class)
.withBean("customServiceConfigurer", GrpcServiceConfigurer.class, () -> configurer)
new ApplicationContextRunner().withUserConfiguration(DefaultGrpcServiceDiscovererTestsConfig.class)
.run((context) -> {
assertThat(context).getBean(DefaultGrpcServiceDiscoverer.class)
.extracting(DefaultGrpcServiceDiscoverer::findServices, InstanceOfAssertFactories.LIST)
.containsExactly(DefaultGrpcServiceDiscovererTestsConfig.SERVICE_DEF_B,
DefaultGrpcServiceDiscovererTestsConfig.SERVICE_DEF_A);
TestServiceConfigurer configurer = context.getBean(TestServiceConfigurer.class);
assertThat(configurer.invocations).hasSize(2);
assertThat(configurer.invocations.keySet()).containsExactly(SERVICE_B, SERVICE_A);
assertThat(configurer.invocations).containsEntry(SERVICE_B, null);
@@ -78,26 +66,37 @@ class DefaultGrpcServiceDiscovererTests {
@Configuration(proxyBeanMethods = false)
static class DefaultGrpcServiceDiscovererTestsConfig {
static BindableService SERVICE_A = mock();
static BindableService SERVICE_A = Mockito.mock();
static ServerServiceDefinition SERVICE_DEF_A = mock();
static ServerServiceDefinition SERVICE_DEF_A = Mockito.mock();
static BindableService SERVICE_B = mock();
static BindableService SERVICE_B = Mockito.mock();
static ServerServiceDefinition SERVICE_DEF_B = mock();
static ServerServiceDefinition SERVICE_DEF_B = Mockito.mock();
@Bean
TestServiceConfigurer testServiceConfigurer() {
return new TestServiceConfigurer();
}
@Bean
GrpcServiceDiscoverer grpcServiceDiscoverer(GrpcServiceConfigurer grpcServiceConfigurer,
ApplicationContext applicationContext) {
return new DefaultGrpcServiceDiscoverer(grpcServiceConfigurer, applicationContext);
}
@GrpcService
@Bean
@Order(200)
BindableService serviceA() {
when(SERVICE_A.bindService()).thenReturn(SERVICE_DEF_A);
Mockito.when(SERVICE_A.bindService()).thenReturn(SERVICE_DEF_A);
return SERVICE_A;
}
@Bean
@Order(100)
BindableService serviceB() {
when(SERVICE_B.bindService()).thenReturn(SERVICE_DEF_B);
Mockito.when(SERVICE_B.bindService()).thenReturn(SERVICE_DEF_B);
return SERVICE_B;
}

View File

@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.grpc.autoconfigure.server;
package org.springframework.grpc.server.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import java.util.List;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -25,8 +27,6 @@ import org.springframework.core.annotation.AnnotationUtils;
import io.grpc.ServerInterceptor;
import java.util.List;
/**
* Tests for {@link GrpcServiceInfo}.
*/

View File

@@ -29,9 +29,12 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.grpc.autoconfigure.common.codec.GrpcCodecConfiguration;
import org.springframework.grpc.server.GrpcServerFactory;
import org.springframework.grpc.server.GrpcServiceDiscoverer;
import org.springframework.grpc.server.ServerBuilderCustomizer;
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
import org.springframework.grpc.server.service.DefaultGrpcServiceConfigurer;
import org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;
import org.springframework.grpc.server.service.GrpcServiceConfigurer;
import org.springframework.grpc.server.service.GrpcServiceDiscoverer;
import io.grpc.BindableService;
import io.grpc.CompressorRegistry;

View File

@@ -31,7 +31,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.grpc.server.GrpcServiceDiscoverer;
import org.springframework.grpc.server.service.GrpcServiceDiscoverer;
import org.springframework.util.unit.DataSize;
import io.grpc.BindableService;

View File

@@ -29,10 +29,10 @@ import org.springframework.boot.ssl.SslBundles;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.grpc.server.GrpcServerFactory;
import org.springframework.grpc.server.GrpcServiceDiscoverer;
import org.springframework.grpc.server.NettyGrpcServerFactory;
import org.springframework.grpc.server.ServerBuilderCustomizer;
import org.springframework.grpc.server.ShadedNettyGrpcServerFactory;
import org.springframework.grpc.server.service.GrpcServiceDiscoverer;
import io.grpc.netty.NettyServerBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;

View File

@@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.grpc.server.GlobalServerInterceptor;
import io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor;
import io.micrometer.observation.ObservationRegistry;

View File

@@ -34,6 +34,7 @@ import org.mockito.InOrder;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
@@ -42,11 +43,13 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.grpc.server.GrpcServerFactory;
import org.springframework.grpc.server.GrpcServiceDiscoverer;
import org.springframework.grpc.server.NettyGrpcServerFactory;
import org.springframework.grpc.server.ServerBuilderCustomizer;
import org.springframework.grpc.server.ShadedNettyGrpcServerFactory;
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
import org.springframework.grpc.server.service.DefaultGrpcServiceConfigurer;
import org.springframework.grpc.server.service.GrpcServiceConfigurer;
import org.springframework.grpc.server.service.GrpcServiceDiscoverer;
import io.grpc.BindableService;
import io.grpc.Grpc;

View File

@@ -21,9 +21,11 @@ import static org.assertj.core.api.Assertions.assertThat;
import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.grpc.server.GlobalServerInterceptor;
import io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor;
import io.micrometer.observation.ObservationRegistry;