Skip to content

Commit b47259d

Browse files
committed
Allow filtering of global server interceptors
This commit adds support for filtering the server-side global interceptors. Resolves #208 Signed-off-by: Chris Bono <[email protected]>
1 parent 94b9ef9 commit b47259d

File tree

9 files changed

+276
-50
lines changed

9 files changed

+276
-50
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2024-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.grpc.server;
18+
19+
import io.grpc.Server;
20+
import io.grpc.ServerServiceDefinition;
21+
22+
/**
23+
* Marker interface for {@link GrpcServerFactory} that is to be handled by the servlet
24+
* container.
25+
*
26+
* @author Chris Bono
27+
*/
28+
public class ServletGrpcServerFactory implements GrpcServerFactory {
29+
30+
/**
31+
* Default instance of marker interface.
32+
*/
33+
public static ServletGrpcServerFactory INSTANCE = new ServletGrpcServerFactory();
34+
35+
@Override
36+
public Server createServer() {
37+
throw new UnsupportedOperationException("Marker interface only");
38+
}
39+
40+
@Override
41+
public void addService(ServerServiceDefinition service) {
42+
throw new UnsupportedOperationException("Marker interface only");
43+
}
44+
45+
}

spring-grpc-core/src/main/java/org/springframework/grpc/server/service/DefaultGrpcServiceConfigurer.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@
2020
import java.util.List;
2121

2222
import org.springframework.beans.factory.InitializingBean;
23+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
24+
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
2325
import org.springframework.context.ApplicationContext;
26+
import org.springframework.core.log.LogAccessor;
2427
import org.springframework.grpc.internal.ApplicationContextBeanLookupUtils;
2528
import org.springframework.grpc.server.GlobalServerInterceptor;
29+
import org.springframework.grpc.server.GrpcServerFactory;
2630
import org.springframework.lang.Nullable;
31+
import org.springframework.util.Assert;
2732

2833
import io.grpc.BindableService;
2934
import io.grpc.ServerInterceptor;
@@ -38,37 +43,65 @@
3843
*/
3944
public class DefaultGrpcServiceConfigurer implements GrpcServiceConfigurer, InitializingBean {
4045

46+
private final LogAccessor log = new LogAccessor(getClass());
47+
4148
private final ApplicationContext applicationContext;
4249

4350
private List<ServerInterceptor> globalInterceptors;
4451

52+
private ServerInterceptorFilter interceptorFilter;
53+
4554
public DefaultGrpcServiceConfigurer(ApplicationContext applicationContext) {
4655
this.applicationContext = applicationContext;
4756
}
4857

4958
@Override
5059
public void afterPropertiesSet() {
5160
this.globalInterceptors = findGlobalInterceptors();
61+
this.interceptorFilter = findInterceptorFilter();
5262
}
5363

5464
@Override
55-
public ServerServiceDefinition configure(ServerServiceDefinitionSpec serviceDefinitionSpec) {
56-
return bindInterceptors(serviceDefinitionSpec.service(), serviceDefinitionSpec.serviceInfo());
65+
public ServerServiceDefinition configure(ServerServiceDefinitionSpec serviceSpec, GrpcServerFactory serverFactory) {
66+
Assert.notNull(serviceSpec, () -> "serviceSpec must not be null");
67+
Assert.notNull(serverFactory, () -> "serverFactory must not be null");
68+
return bindInterceptors(serviceSpec.service(), serviceSpec.serviceInfo(), serverFactory);
5769
}
5870

5971
private List<ServerInterceptor> findGlobalInterceptors() {
6072
return ApplicationContextBeanLookupUtils.getBeansWithAnnotation(this.applicationContext,
6173
ServerInterceptor.class, GlobalServerInterceptor.class);
6274
}
6375

76+
private ServerInterceptorFilter findInterceptorFilter() {
77+
try {
78+
return this.applicationContext.getBean(ServerInterceptorFilter.class);
79+
}
80+
catch (NoUniqueBeanDefinitionException noUniqueBeanEx) {
81+
this.log.warn(noUniqueBeanEx,
82+
() -> "No unique ServerInterceptorFilter bean found. Consider defining a single bean or marking one as @Primary");
83+
return null;
84+
}
85+
catch (NoSuchBeanDefinitionException ignored) {
86+
this.log.debug(
87+
() -> "No ServerInterceptorFilter bean found - filtering will not be applied to server interceptors.");
88+
return null;
89+
}
90+
}
91+
6492
private ServerServiceDefinition bindInterceptors(BindableService bindableService,
65-
@Nullable GrpcServiceInfo serviceInfo) {
93+
@Nullable GrpcServiceInfo serviceInfo, GrpcServerFactory serverFactory) {
6694
var serviceDef = bindableService.bindService();
95+
96+
// Add and filter global interceptors first
97+
List<ServerInterceptor> allInterceptors = new ArrayList<>(this.globalInterceptors);
98+
if (this.interceptorFilter != null) {
99+
allInterceptors
100+
.removeIf(interceptor -> !this.interceptorFilter.filter(interceptor, serviceDef, serverFactory));
101+
}
67102
if (serviceInfo == null) {
68-
return ServerInterceptors.interceptForward(serviceDef, this.globalInterceptors);
103+
return ServerInterceptors.interceptForward(serviceDef, allInterceptors);
69104
}
70-
// Add global interceptors first
71-
List<ServerInterceptor> allInterceptors = new ArrayList<>(this.globalInterceptors);
72105
// Add interceptors by type
73106
Arrays.stream(serviceInfo.interceptors())
74107
.forEachOrdered(

spring-grpc-core/src/main/java/org/springframework/grpc/server/service/GrpcServiceConfigurer.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.grpc.server.service;
1818

19+
import org.springframework.grpc.server.GrpcServerFactory;
20+
1921
import io.grpc.ServerServiceDefinition;
2022

2123
/**
@@ -29,12 +31,14 @@
2931
public interface GrpcServiceConfigurer {
3032

3133
/**
32-
* Configure and bind a gRPC service spec resulting in a service definition that can
34+
* Configure and bind a gRPC server spec resulting in a service definition that can
3335
* then be added to a gRPC server.
3436
* @param serviceSpec the spec containing the info about the service
35-
* @return bound and configured service definition that is ready to be added to the
37+
* @param serverFactory the factory that provides the server that the service will be
38+
* added to
39+
* @return bound and configured service definition that is ready to be added to a
3640
* server
3741
*/
38-
ServerServiceDefinition configure(ServerServiceDefinitionSpec serviceSpec);
42+
ServerServiceDefinition configure(ServerServiceDefinitionSpec serviceSpec, GrpcServerFactory serverFactory);
3943

4044
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2023-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.grpc.server.service;
17+
18+
import org.springframework.grpc.server.GrpcServerFactory;
19+
20+
import io.grpc.ServerInterceptor;
21+
import io.grpc.ServerServiceDefinition;
22+
23+
/**
24+
* Strategy to determine whether a global {@link ServerInterceptor server interceptor}
25+
* should be applied to {@link ServerServiceDefinition gRPC service}.
26+
*
27+
* @author Chris Bono
28+
*/
29+
@FunctionalInterface
30+
public interface ServerInterceptorFilter {
31+
32+
/**
33+
* Determine whether an interceptor should be applied to a service when the service is
34+
* running on a server provided by the given server factory.
35+
* @param interceptor the server interceptor under consideration.
36+
* @param service the service being added.
37+
* @param serverFactory the server factory in use.
38+
* @return {@code true} if the interceptor should be included; {@code false}
39+
* otherwise.
40+
*/
41+
boolean filter(ServerInterceptor interceptor, ServerServiceDefinition service, GrpcServerFactory serverFactory);
42+
43+
}

0 commit comments

Comments
 (0)