Skip to content

Commit 73a51f8

Browse files
committed
Merge remote-tracking branch 'origin/main' into 8-codec-support
# Conflicts: # spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientAutoConfiguration.java # spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfiguration.java
2 parents 786951e + c07d4de commit 73a51f8

File tree

15 files changed

+270
-212
lines changed

15 files changed

+270
-212
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
class GrpcServerIntegrationTests {
4444

4545
@Nested
46-
@SpringBootTest(properties = { "spring.grpc.server.address=0.0.0.0", "spring.grpc.server.port=0" })
46+
@SpringBootTest(properties = { "spring.grpc.server.host=0.0.0.0", "spring.grpc.server.port=0" })
4747
class ServerWithAnyIPv4AddressAndRandomPort {
4848

4949
@Test
@@ -55,7 +55,7 @@ void servesResponseToClientWithAnyIPv4AddressAndRandomPort(@Autowired GrpcChanne
5555
}
5656

5757
@Nested
58-
@SpringBootTest(properties = { "spring.grpc.server.address=::", "spring.grpc.server.port=0" })
58+
@SpringBootTest(properties = { "spring.grpc.server.host=::", "spring.grpc.server.port=0" })
5959
class ServerWithAnyIPv6AddressAndRandomPort {
6060

6161
@Test
@@ -67,7 +67,7 @@ void servesResponseToClientWithAnyIPv4AddressAndRandomPort(@Autowired GrpcChanne
6767
}
6868

6969
@Nested
70-
@SpringBootTest(properties = { "spring.grpc.server.address=127.0.0.1", "spring.grpc.server.port=0" })
70+
@SpringBootTest(properties = { "spring.grpc.server.host=127.0.0.1", "spring.grpc.server.port=0" })
7171
class ServerWithLocalhostAndRandomPort {
7272

7373
@Test
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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.internal;
17+
18+
public class GrpcUtils {
19+
20+
public static int DEFAULT_PORT = 9090;
21+
22+
public static int getPort(String address) {
23+
String value = address;
24+
if (value.contains(":")) {
25+
value = value.substring(value.lastIndexOf(":") + 1);
26+
}
27+
if (value.contains("/")) {
28+
value = value.substring(0, value.indexOf("/"));
29+
}
30+
if (value.matches("[0-9]+")) {
31+
return Integer.parseInt(value);
32+
}
33+
if (address.startsWith("unix:")) {
34+
return -1;
35+
}
36+
return DEFAULT_PORT;
37+
}
38+
39+
}

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@
2222
import java.util.Set;
2323

2424
import com.google.common.collect.Lists;
25+
26+
import io.grpc.Grpc;
27+
import io.grpc.InsecureServerCredentials;
2528
import io.grpc.Server;
2629
import io.grpc.ServerBuilder;
30+
import io.grpc.ServerCredentials;
2731
import io.grpc.ServerProvider;
2832
import io.grpc.ServerServiceDefinition;
33+
2934
import org.apache.commons.logging.Log;
3035
import org.apache.commons.logging.LogFactory;
36+
import org.springframework.grpc.internal.GrpcUtils;
3137

3238
/**
3339
* Default implementation for {@link GrpcServerFactory gRPC service factories}.
@@ -48,25 +54,17 @@ public class DefaultGrpcServerFactory<T extends ServerBuilder<T>> implements Grp
4854

4955
private final String address;
5056

51-
private final int port;
52-
5357
private final List<ServerBuilderCustomizer<T>> serverBuilderCustomizers;
5458

55-
public DefaultGrpcServerFactory(String address, int port,
56-
List<ServerBuilderCustomizer<T>> serverBuilderCustomizers) {
59+
public DefaultGrpcServerFactory(String address, List<ServerBuilderCustomizer<T>> serverBuilderCustomizers) {
5760
this.address = address;
58-
this.port = port;
5961
this.serverBuilderCustomizers = Objects.requireNonNull(serverBuilderCustomizers, "serverBuilderCustomizers");
6062
}
6163

62-
protected String getAddress() {
64+
protected String address() {
6365
return this.address;
6466
}
6567

66-
protected int getPort() {
67-
return this.port;
68-
}
69-
7068
@Override
7169
public Server createServer() {
7270
T builder = newServerBuilder();
@@ -85,7 +83,23 @@ public void addService(ServerServiceDefinition service) {
8583
*/
8684
@SuppressWarnings("unchecked")
8785
protected T newServerBuilder() {
88-
return (T) ServerBuilder.forPort(port);
86+
return (T) Grpc.newServerBuilderForPort(port(), credentials());
87+
}
88+
89+
/**
90+
* Returns the port number on which the server should listen. Use 0 to let the system
91+
* choose a port. Use -1 to denote that this server does not listen on a socket.
92+
* @return the port number
93+
*/
94+
protected int port() {
95+
return GrpcUtils.getPort(address());
96+
}
97+
98+
/**
99+
* @return some server credentials (default is insecure)
100+
*/
101+
protected ServerCredentials credentials() {
102+
return InsecureServerCredentials.create();
89103
}
90104

91105
/**

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

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
package org.springframework.grpc.server;
1818

19-
import java.net.InetSocketAddress;
2019
import java.util.List;
2120

22-
import com.google.common.net.InetAddresses;
21+
import javax.net.ssl.KeyManagerFactory;
22+
23+
import io.grpc.ServerCredentials;
24+
import io.grpc.TlsServerCredentials;
2325
import io.grpc.netty.NettyServerBuilder;
2426
import io.netty.channel.epoll.EpollEventLoopGroup;
2527
import io.netty.channel.epoll.EpollServerDomainSocketChannel;
@@ -33,34 +35,33 @@
3335
*/
3436
public class NettyGrpcServerFactory extends DefaultGrpcServerFactory<NettyServerBuilder> {
3537

36-
private static final String ANY_IP_ADDRESS = "*";
38+
private KeyManagerFactory keyManager;
3739

38-
public NettyGrpcServerFactory(String address, int port,
40+
public NettyGrpcServerFactory(String address, KeyManagerFactory keyManager,
3941
List<ServerBuilderCustomizer<NettyServerBuilder>> serverBuilderCustomizers) {
40-
super(address, port, serverBuilderCustomizers);
42+
super(address, serverBuilderCustomizers);
43+
this.keyManager = keyManager;
4144
}
4245

43-
/**
44-
* Creates a new server builder.
45-
* @return The newly created server builder.
46-
*/
46+
@Override
4747
protected NettyServerBuilder newServerBuilder() {
48-
String address = getAddress();
49-
int port = getPort();
50-
if (address != null) {
51-
if (address.startsWith("unix:")) {
52-
String path = address.substring(5);
53-
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
54-
.channelType(EpollServerDomainSocketChannel.class)
55-
.bossEventLoopGroup(new EpollEventLoopGroup(1))
56-
.workerEventLoopGroup(new EpollEventLoopGroup());
57-
}
58-
if (!ANY_IP_ADDRESS.equals(address)) {
59-
return NettyServerBuilder.forAddress(new InetSocketAddress(InetAddresses.forString(address), port));
60-
}
61-
// TODO: Add more support for address resolution
48+
String address = address();
49+
if (address.startsWith("unix:")) {
50+
String path = address.substring(5);
51+
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
52+
.channelType(EpollServerDomainSocketChannel.class)
53+
.bossEventLoopGroup(new EpollEventLoopGroup(1))
54+
.workerEventLoopGroup(new EpollEventLoopGroup());
6255
}
6356
return super.newServerBuilder();
6457
}
6558

59+
@Override
60+
protected ServerCredentials credentials() {
61+
if (this.keyManager == null || port() == -1) {
62+
return super.credentials();
63+
}
64+
return TlsServerCredentials.newBuilder().keyManager(this.keyManager.getKeyManagers()).build();
65+
}
66+
6667
}

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

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
package org.springframework.grpc.server;
1818

19-
import java.net.InetSocketAddress;
2019
import java.util.List;
2120

22-
import com.google.common.net.InetAddresses;
21+
import javax.net.ssl.KeyManagerFactory;
22+
23+
import io.grpc.ServerCredentials;
24+
import io.grpc.TlsServerCredentials;
2325
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
2426
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup;
2527
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerDomainSocketChannel;
@@ -33,34 +35,33 @@
3335
*/
3436
public class ShadedNettyGrpcServerFactory extends DefaultGrpcServerFactory<NettyServerBuilder> {
3537

36-
private static final String ANY_IP_ADDRESS = "*";
38+
private KeyManagerFactory keyManager;
3739

38-
public ShadedNettyGrpcServerFactory(String address, int port,
40+
public ShadedNettyGrpcServerFactory(String address, KeyManagerFactory keyManager,
3941
List<ServerBuilderCustomizer<NettyServerBuilder>> serverBuilderCustomizers) {
40-
super(address, port, serverBuilderCustomizers);
42+
super(address, serverBuilderCustomizers);
43+
this.keyManager = keyManager;
4144
}
4245

43-
/**
44-
* Creates a new server builder.
45-
* @return The newly created server builder.
46-
*/
46+
@Override
4747
protected NettyServerBuilder newServerBuilder() {
48-
String address = getAddress();
49-
int port = getPort();
50-
if (address != null) {
51-
if (address.startsWith("unix:")) {
52-
String path = address.substring(5);
53-
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
54-
.channelType(EpollServerDomainSocketChannel.class)
55-
.bossEventLoopGroup(new EpollEventLoopGroup(1))
56-
.workerEventLoopGroup(new EpollEventLoopGroup());
57-
}
58-
if (!ANY_IP_ADDRESS.equals(address)) {
59-
return NettyServerBuilder.forAddress(new InetSocketAddress(InetAddresses.forString(address), port));
60-
}
61-
// TODO: Add more support for address resolution
48+
String address = address();
49+
if (address.startsWith("unix:")) {
50+
String path = address.substring(5);
51+
return NettyServerBuilder.forAddress(new DomainSocketAddress(path))
52+
.channelType(EpollServerDomainSocketChannel.class)
53+
.bossEventLoopGroup(new EpollEventLoopGroup(1))
54+
.workerEventLoopGroup(new EpollEventLoopGroup());
6255
}
6356
return super.newServerBuilder();
6457
}
6558

59+
@Override
60+
protected ServerCredentials credentials() {
61+
if (this.keyManager == null || port() == -1) {
62+
return super.credentials();
63+
}
64+
return TlsServerCredentials.newBuilder().keyManager(this.keyManager.getKeyManagers()).build();
65+
}
66+
6667
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.springframework.grpc.internal;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
class GrpcUtilsTests {
8+
9+
@Test
10+
void testGetPortFromAddress() {
11+
assertEquals(8080, GrpcUtils.getPort("localhost:8080"));
12+
}
13+
14+
@Test
15+
void testGetNoPort() {
16+
assertEquals(9090, GrpcUtils.getPort("localhost"));
17+
}
18+
19+
@Test
20+
void testGetPortFromAddressWithPath() {
21+
String address = "example.com:1234/path";
22+
assertEquals(1234, GrpcUtils.getPort(address));
23+
}
24+
25+
@Test
26+
void testGetDomainAddress() {
27+
String address = "unix:/some/file/somewhere";
28+
assertEquals(-1, GrpcUtils.getPort(address));
29+
}
30+
31+
@Test
32+
void testGetStaticSchema() {
33+
String address = "static://localhost";
34+
assertEquals(9090, GrpcUtils.getPort(address));
35+
}
36+
37+
@Test
38+
void testGetInvalidAddress() {
39+
String address = "invalid:broken";
40+
assertEquals(9090, GrpcUtils.getPort(address)); // -1?
41+
}
42+
43+
}

spring-grpc-docs/src/main/antora/modules/ROOT/partials/_configprops.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
|spring.grpc.client.default-channel.ssl.bundle | | SSL bundle name.
1717
|spring.grpc.client.default-channel.ssl.enabled | | Whether to enable SSL support. Enabled automatically if "bundle" is provided unless specified otherwise.
1818
|spring.grpc.client.default-channel.user-agent | |
19-
|spring.grpc.server.address | `+++*+++` | Server address to bind to. The default is any IP address ('*').
19+
|spring.grpc.server.address | | The address to bind to. could be a host:port combination or a pseudo URL like static://host:port. Can not be set if host or port are set independently.
20+
|spring.grpc.server.host | `+++*+++` | Server address to bind to. The default is any IP address ('*').
2021
|spring.grpc.server.keep-alive.max-age | | Maximum time a connection may exist before being gracefully terminated (default infinite).
2122
|spring.grpc.server.keep-alive.max-age-grace | | Maximum time for graceful connection termination (default infinite).
2223
|spring.grpc.server.keep-alive.max-idle | | Maximum time a connection can remain idle before being gracefully terminated (default infinite).

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import org.springframework.grpc.client.ShadedNettyGrpcChannelFactory;
3333
import org.springframework.grpc.client.VirtualTargets;
3434

35-
import io.grpc.ManagedChannelBuilder;
3635
import io.grpc.netty.GrpcSslContexts;
3736
import io.grpc.netty.NettyChannelBuilder;
3837
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
@@ -131,21 +130,6 @@ private static io.grpc.netty.NegotiationType of(final NegotiationType negotiatio
131130

132131
}
133132

134-
@Configuration(proxyBeanMethods = false)
135-
@ConditionalOnClass(ManagedChannelBuilder.class)
136-
@ConditionalOnMissingBean(GrpcChannelFactory.class)
137-
public static class DefaultChannelFactoryConfiguration {
138-
139-
@Bean
140-
public DefaultGrpcChannelFactory defaultGrpcChannelFactory(final List<GrpcChannelConfigurer> configurers,
141-
GrpcClientProperties channels) {
142-
DefaultGrpcChannelFactory factory = new DefaultGrpcChannelFactory(configurers);
143-
factory.setVirtualTargets(new NamedChannelVirtualTargets(channels));
144-
return factory;
145-
}
146-
147-
}
148-
149133
static class NamedChannelVirtualTargets implements VirtualTargets {
150134

151135
private final GrpcClientProperties channels;

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@
3333
@Configuration(proxyBeanMethods = false)
3434
@EnableConfigurationProperties(GrpcClientProperties.class)
3535
@Import({ GrpcChannelFactoryConfigurations.ShadedNettyChannelFactoryConfiguration.class,
36-
GrpcChannelFactoryConfigurations.NettyChannelFactoryConfiguration.class,
37-
GrpcChannelFactoryConfigurations.DefaultChannelFactoryConfiguration.class, GrpcCodecConfiguration.class })
36+
GrpcChannelFactoryConfigurations.NettyChannelFactoryConfiguration.class, GrpcCodecConfiguration.class })
3837
public class GrpcClientAutoConfiguration {
3938

4039
@Bean

spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3131
import org.springframework.context.ApplicationEventPublisher;
3232
import org.springframework.context.annotation.Bean;
33+
import org.springframework.context.annotation.Conditional;
3334
import org.springframework.context.annotation.Import;
3435
import org.springframework.core.Ordered;
3536
import org.springframework.grpc.autoconfigure.common.codec.GrpcCodecConfiguration;
@@ -52,8 +53,7 @@
5253
@ConditionalOnBean(BindableService.class)
5354
@EnableConfigurationProperties(GrpcServerProperties.class)
5455
@Import({ GrpcServerFactoryConfigurations.ShadedNettyServerFactoryConfiguration.class,
55-
GrpcServerFactoryConfigurations.NettyServerFactoryConfiguration.class,
56-
GrpcServerFactoryConfigurations.ServiceProviderServerFactoryConfiguration.class, GrpcCodecConfiguration.class })
56+
GrpcServerFactoryConfigurations.NettyServerFactoryConfiguration.class, GrpcCodecConfiguration.class })
5757
public class GrpcServerAutoConfiguration {
5858

5959
private final GrpcServerProperties properties;
@@ -62,6 +62,7 @@ public class GrpcServerAutoConfiguration {
6262
this.properties = properties;
6363
}
6464

65+
@ConditionalOnBean(GrpcServerFactory.class)
6566
@ConditionalOnMissingBean
6667
@Bean
6768
GrpcServerLifecycle grpcServerLifecycle(GrpcServerFactory factory, ApplicationEventPublisher eventPublisher) {

0 commit comments

Comments
 (0)