Skip to content

Commit f38a16f

Browse files
committed
Add support for external client (channel) config
Fixes #11
1 parent 9c20aa0 commit f38a16f

File tree

8 files changed

+632
-15
lines changed

8 files changed

+632
-15
lines changed

samples/grpc-server/src/test/java/org/springframework/grpc/sample/AnotherApplicationTests.java

+18-7
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,41 @@
33
import static org.junit.jupiter.api.Assertions.assertEquals;
44

55
import org.junit.jupiter.api.Test;
6+
import org.springframework.beans.factory.annotation.Autowired;
67
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.boot.test.context.TestConfiguration;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.grpc.client.GrpcChannelFactory;
711
import org.springframework.grpc.sample.proto.HelloReply;
812
import org.springframework.grpc.sample.proto.HelloRequest;
913
import org.springframework.grpc.sample.proto.SimpleGrpc;
1014
import org.springframework.test.annotation.DirtiesContext;
1115

12-
import io.grpc.Grpc;
13-
import io.grpc.InsecureChannelCredentials;
14-
15-
@SpringBootTest
16+
@SpringBootTest(properties = "spring.grpc.client.channels.test.address=static://0.0.0.0:9090")
1617
@DirtiesContext
1718
class AnotherApplicationTests {
1819

20+
@Autowired
21+
private SimpleGrpc.SimpleBlockingStub stub;
22+
1923
@Test
2024
void contextLoads() {
2125
}
2226

2327
@Test
2428
void serverResponds() {
25-
var channel = Grpc.newChannelBuilderForAddress("0.0.0.0", 9090, InsecureChannelCredentials.create()).build();
26-
var stub = SimpleGrpc.newBlockingStub(channel);
2729
HelloReply response = stub.sayHello(HelloRequest.newBuilder().setName("Alien").build());
2830
assertEquals("Hello ==> Alien", response.getMessage());
29-
channel.shutdown();
31+
}
32+
33+
@TestConfiguration
34+
static class ExtraConfiguration {
35+
36+
@Bean
37+
SimpleGrpc.SimpleBlockingStub stub(GrpcChannelFactory channels) {
38+
return SimpleGrpc.newBlockingStub(channels.createChannel("test").build());
39+
}
40+
3041
}
3142

3243
}

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,30 @@ public class DefaultGrpcChannelFactory implements GrpcChannelFactory, Disposable
3737
private final List<GrpcChannelConfigurer> configurers = new ArrayList<>();
3838

3939
public DefaultGrpcChannelFactory() {
40+
this(List.of());
4041
}
4142

4243
public DefaultGrpcChannelFactory(List<GrpcChannelConfigurer> configurers) {
43-
configurers.addAll(configurers);
44+
this.configurers.addAll(configurers);
4445
}
4546

4647
@Override
4748
public ManagedChannelBuilder<?> createChannel(String authority) {
4849
ManagedChannelBuilder<?> target = builders.computeIfAbsent(authority, path -> {
49-
ManagedChannelBuilder<?> builder = Grpc.newChannelBuilder(path, InsecureChannelCredentials.create());
50+
ManagedChannelBuilder<?> builder = newChannel(path);
5051
for (GrpcChannelConfigurer configurer : configurers) {
51-
configurer.accept(path, builder);
52+
configurer.configure(path, builder);
5253
}
5354
return builder;
5455
});
5556
return new DisposableChannelBuilder(authority, target);
5657

5758
}
5859

60+
protected ManagedChannelBuilder<?> newChannel(String path) {
61+
return Grpc.newChannelBuilder(path, InsecureChannelCredentials.create());
62+
}
63+
5964
@Override
6065
public void destroy() throws Exception {
6166
for (ManagedChannel channel : channels.values()) {

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
*/
1616
package org.springframework.grpc.client;
1717

18-
import java.util.function.BiConsumer;
19-
2018
import io.grpc.ManagedChannelBuilder;
2119

2220
@FunctionalInterface
23-
public interface GrpcChannelConfigurer extends BiConsumer<String, ManagedChannelBuilder<?>> {
21+
public interface GrpcChannelConfigurer {
22+
23+
public void configure(String authority, ManagedChannelBuilder<?> builder);
2424

2525
}

spring-grpc-spring-boot-autoconfigure/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
<artifactId>spring-boot-starter</artifactId>
4343
</dependency>
4444

45+
<dependency>
46+
<groupId>io.grpc</groupId>
47+
<artifactId>grpc-netty-shaded</artifactId>
48+
<optional>true</optional>
49+
</dependency>
50+
4551
<!-- test dependencies -->
4652

4753
<dependency>

spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientAutoConfiguration.java

+73-2
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,93 @@
1515
*/
1616
package org.springframework.grpc.autoconfigure.client;
1717

18+
import java.net.URI;
1819
import java.util.List;
20+
import java.util.concurrent.TimeUnit;
1921

2022
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
23+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
24+
import org.springframework.boot.ssl.SslBundle;
25+
import org.springframework.boot.ssl.SslBundles;
2126
import org.springframework.context.annotation.Bean;
2227
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.grpc.autoconfigure.client.GrpcClientProperties.NamedChannel;
2329
import org.springframework.grpc.client.DefaultGrpcChannelFactory;
2430
import org.springframework.grpc.client.GrpcChannelConfigurer;
2531
import org.springframework.grpc.client.GrpcChannelFactory;
2632

33+
import io.grpc.ManagedChannelBuilder;
34+
2735
@Configuration(proxyBeanMethods = false)
36+
@EnableConfigurationProperties(GrpcClientProperties.class)
2837
public class GrpcClientAutoConfiguration {
2938

3039
@Bean
3140
@ConditionalOnMissingBean(GrpcChannelFactory.class)
32-
public DefaultGrpcChannelFactory defaultGrpcChannelFactory(final List<GrpcChannelConfigurer> configurers) {
33-
return new DefaultGrpcChannelFactory(configurers);
41+
public DefaultGrpcChannelFactory defaultGrpcChannelFactory(final List<GrpcChannelConfigurer> configurers,
42+
GrpcClientProperties channels) {
43+
return new DefaultGrpcChannelFactory(configurers) {
44+
@Override
45+
public ManagedChannelBuilder<?> newChannel(String authority) {
46+
if (channels.getChannels().containsKey(authority)) {
47+
NamedChannel channel = channels.getChannels().get(authority);
48+
URI address = channel.getAddress();
49+
if (address.getScheme().equals("static") || address.getScheme().equals("tcp")) {
50+
return super.newChannel(address.getAuthority());
51+
}
52+
return super.newChannel(address.toString());
53+
}
54+
return super.newChannel(authority);
55+
}
56+
};
57+
}
58+
59+
@Bean
60+
public GrpcChannelConfigurer sslGrpcChannelConfigurer(GrpcClientProperties channels, SslBundles bundles) {
61+
return (authority, builder) -> {
62+
for (String name : channels.getChannels().keySet()) {
63+
if (authority.equals(name)) {
64+
NamedChannel channel = channels.getChannels().get(name);
65+
if (channel.getSsl().isEnabled() && channel.getSsl().getBundle() != null) {
66+
SslBundle bundle = bundles.getBundle(channel.getSsl().getBundle());
67+
if (NettyChannelFactoryHelper.isAvailable()) {
68+
NettyChannelFactoryHelper.sslContext(builder, bundle);
69+
}
70+
else if (ShadedNettyChannelFactoryHelper.isAvailable()) {
71+
ShadedNettyChannelFactoryHelper.sslContext(builder, bundle);
72+
}
73+
else {
74+
throw new IllegalStateException("Netty is not available");
75+
}
76+
}
77+
else {
78+
// builder.usePlaintext();
79+
}
80+
if (channel.getUserAgent() != null) {
81+
builder.userAgent(channel.getUserAgent());
82+
}
83+
if (channel.getDefaultLoadBalancingPolicy() != null) {
84+
builder.defaultLoadBalancingPolicy(channel.getDefaultLoadBalancingPolicy());
85+
}
86+
if (channel.getMaxInboundMessageSize() != null) {
87+
builder.maxInboundMessageSize((int) channel.getMaxInboundMessageSize().toBytes());
88+
}
89+
if (channel.getMaxInboundMetadataSize() != null) {
90+
builder.maxInboundMetadataSize((int) channel.getMaxInboundMetadataSize().toBytes());
91+
}
92+
if (channel.getKeepAliveTime() != null) {
93+
builder.keepAliveTime(channel.getKeepAliveTime().toNanos(), TimeUnit.NANOSECONDS);
94+
}
95+
if (channel.getKeepAliveTimeout() != null) {
96+
builder.keepAliveTimeout(channel.getKeepAliveTimeout().toNanos(), TimeUnit.NANOSECONDS);
97+
}
98+
builder.keepAliveWithoutCalls(channel.isKeepAliveWithoutCalls());
99+
if (channel.getIdleTimeout() != null) {
100+
builder.idleTimeout(channel.getIdleTimeout().toNanos(), TimeUnit.NANOSECONDS);
101+
}
102+
}
103+
}
104+
};
34105
}
35106

36107
}

0 commit comments

Comments
 (0)