Skip to content

Commit a3d7ba6

Browse files
committed
Split bean registration and creation for stubs
GrpcClientRegistry was responsible for both, which causes lifecycle issues when users don't follow recommendations. This change pushes the bean registration firmly down a level into an ImportBeanDefinitionRegistrar. Also helps with AOT because the AOT processor only runs the IBDR at build time.
1 parent 326c075 commit a3d7ba6

File tree

13 files changed

+437
-492
lines changed

13 files changed

+437
-492
lines changed

samples/grpc-oauth2/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java

+6-9
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import org.springframework.experimental.boot.test.context.OAuth2ClientProviderIssuerUri;
2323
import org.springframework.grpc.client.ChannelBuilderOptions;
2424
import org.springframework.grpc.client.ImportGrpcClients;
25-
import org.springframework.grpc.client.GrpcClientRegistryCustomizer;
25+
import org.springframework.grpc.client.GrpcClientFactoryCustomizer;
2626
import org.springframework.grpc.client.interceptor.security.BearerTokenAuthenticationInterceptor;
2727
import org.springframework.grpc.sample.proto.HelloReply;
2828
import org.springframework.grpc.sample.proto.HelloRequest;
@@ -41,7 +41,7 @@
4141
import io.grpc.stub.StreamObserver;
4242

4343
@SpringBootTest(properties = { "spring.grpc.server.port=0",
44-
"spring.grpc.client.channels.stub.address=static://0.0.0.0:${local.grpc.port}" })
44+
"spring.grpc.client.default-channel.address=static://0.0.0.0:${local.grpc.port}" })
4545
@DirtiesContext
4646
public class GrpcServerApplicationTests {
4747

@@ -115,6 +115,7 @@ void authenticated() {
115115
@EnableDynamicProperty
116116
@ImportGrpcClients(target = "stub",
117117
types = { SimpleGrpc.SimpleBlockingStub.class, ServerReflectionGrpc.ServerReflectionStub.class })
118+
@ImportGrpcClients(target = "secure", prefix = "secure", types = { SimpleGrpc.SimpleBlockingStub.class })
118119
static class ExtraConfiguration {
119120

120121
private String token;
@@ -129,13 +130,9 @@ static CommonsExecWebServerFactoryBean authServer() {
129130
}
130131

131132
@Bean
132-
GrpcClientRegistryCustomizer stubs(ObjectProvider<ClientRegistrationRepository> context) {
133-
return registry -> registry
134-
.channel("stub",
135-
ChannelBuilderOptions.defaults()
136-
.withInterceptors(List.of(new BearerTokenAuthenticationInterceptor(() -> token(context)))))
137-
.prefix("secure")
138-
.register(SimpleGrpc.SimpleBlockingStub.class);
133+
GrpcClientFactoryCustomizer stubs(ObjectProvider<ClientRegistrationRepository> context) {
134+
return registry -> registry.channel("secure", ChannelBuilderOptions.defaults()
135+
.withInterceptors(List.of(new BearerTokenAuthenticationInterceptor(() -> token(context)))));
139136
}
140137

141138
private String token(ObjectProvider<ClientRegistrationRepository> context) {

samples/grpc-secure/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
import org.springframework.boot.test.context.SpringBootTest;
1616
import org.springframework.boot.test.context.TestConfiguration;
1717
import org.springframework.context.annotation.Bean;
18-
import org.springframework.grpc.client.BlockingStubFactory;
1918
import org.springframework.grpc.client.ChannelBuilderOptions;
19+
import org.springframework.grpc.client.GrpcClientFactoryCustomizer;
2020
import org.springframework.grpc.client.ImportGrpcClients;
21-
import org.springframework.grpc.client.GrpcClientRegistryCustomizer;
2221
import org.springframework.grpc.client.interceptor.security.BasicAuthenticationInterceptor;
2322
import org.springframework.grpc.sample.proto.HelloReply;
2423
import org.springframework.grpc.sample.proto.HelloRequest;
@@ -109,17 +108,14 @@ void basic() {
109108

110109
@TestConfiguration(proxyBeanMethods = false)
111110
@ImportGrpcClients(target = "stub", prefix = "unsecured", types = { SimpleGrpc.SimpleBlockingStub.class })
111+
@ImportGrpcClients(target = "secure", types = { SimpleGrpc.SimpleBlockingStub.class })
112112
@ImportGrpcClients(target = "default", types = { ServerReflectionGrpc.ServerReflectionStub.class })
113113
static class ExtraConfiguration {
114114

115115
@Bean
116-
GrpcClientRegistryCustomizer basicStubs() {
117-
return registry -> registry
118-
.channel("stub",
119-
ChannelBuilderOptions.defaults()
120-
.withInterceptors(List.of(new BasicAuthenticationInterceptor("user", "user"))))
121-
.scan(BlockingStubFactory.class)
122-
.packageClasses(SimpleGrpc.class);
116+
GrpcClientFactoryCustomizer basicStubs() {
117+
return registry -> registry.channel("secure", ChannelBuilderOptions.defaults()
118+
.withInterceptors(List.of(new BasicAuthenticationInterceptor("user", "user"))));
123119
}
124120

125121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2024-2024 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.client;
17+
18+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
19+
import org.springframework.beans.factory.support.RootBeanDefinition;
20+
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
21+
import org.springframework.core.type.AnnotationMetadata;
22+
import org.springframework.grpc.client.GrpcClientFactory.GrpcClientRegistrationSpec;
23+
24+
public abstract class AbstractGrpcClientRegistrar implements ImportBeanDefinitionRegistrar {
25+
26+
@Override
27+
public final void registerBeanDefinitions(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
28+
GrpcClientRegistrationSpec[] specs = collect(meta);
29+
String name = GrpcClientFactoryPostProcessor.class.getName();
30+
for (GrpcClientRegistrationSpec spec : specs) {
31+
GrpcClientFactory.register(registry, spec);
32+
}
33+
if (!registry.containsBeanDefinition(name)) {
34+
registry.registerBeanDefinition(name, new RootBeanDefinition(GrpcClientFactoryPostProcessor.class));
35+
}
36+
}
37+
38+
protected abstract GrpcClientRegistrationSpec[] collect(AnnotationMetadata meta);
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2024-2024 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.client;
17+
18+
import java.util.HashSet;
19+
import java.util.Set;
20+
21+
import org.springframework.core.annotation.AnnotationAttributes;
22+
import org.springframework.core.type.AnnotationMetadata;
23+
import org.springframework.grpc.client.GrpcClientFactory.GrpcClientRegistrationSpec;
24+
import org.springframework.util.ClassUtils;
25+
26+
public class AnnotationGrpcClientRegistrar extends AbstractGrpcClientRegistrar {
27+
28+
@Override
29+
protected GrpcClientRegistrationSpec[] collect(AnnotationMetadata meta) {
30+
Set<AnnotationAttributes> attrs = meta.getMergedRepeatableAnnotationAttributes(ImportGrpcClients.class,
31+
ImportGrpcClients.Container.class, false);
32+
Set<GrpcClientRegistrationSpec> specs = new HashSet<>();
33+
for (AnnotationAttributes attr : attrs) {
34+
specs.add(register(meta, attr));
35+
}
36+
return specs.toArray(new GrpcClientRegistrationSpec[0]);
37+
}
38+
39+
private GrpcClientRegistrationSpec register(AnnotationMetadata meta, AnnotationAttributes attr) {
40+
String target = attr.getString("target");
41+
String prefix = attr.getString("prefix");
42+
Class<?>[] types = attr.getClassArray("types");
43+
Class<?>[] basePackageClasses = attr.getClassArray("basePackageClasses");
44+
String[] basePackages = attr.getStringArray("basePackages");
45+
Class<? extends StubFactory<?>> factory = attr.getClass("factory");
46+
if (factory == UnspecifiedStubFactory.class) {
47+
factory = null;
48+
}
49+
if (types.length == 0 && basePackageClasses.length == 0 && basePackages.length == 0) {
50+
basePackages = new String[] { ClassUtils.getPackageName(meta.getClassName()) };
51+
}
52+
return GrpcClientRegistrationSpec.of(target)
53+
.factory(factory)
54+
.types(types)
55+
.packages(basePackages)
56+
.packageClasses(basePackageClasses)
57+
.prefix(prefix);
58+
}
59+
60+
}

spring-grpc-core/src/main/java/org/springframework/grpc/client/GrpcClientConfiguration.java

-107
This file was deleted.

0 commit comments

Comments
 (0)