Order
This paper mainly studies NettyConfiguration of spring cloud gateway.
NettyConfiguration
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
@Configuration
@ConditionalOnClass(HttpClient.class)
protected static class NettyConfiguration {
@Bean
@ConditionalOnMissingBean
public HttpClient httpClient(@Qualifier("nettyClientOptions") Consumer<? super HttpClientOptions.Builder> options) {
return HttpClient.create(options);
}
@Bean
public Consumer<? super HttpClientOptions.Builder> nettyClientOptions(HttpClientProperties properties) {
return opts -> {
// configure ssl
HttpClientProperties.Ssl ssl = properties.getSsl();
if (ssl.isUseInsecureTrustManager()) {
opts.sslSupport(sslContextBuilder -> {
sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
});
}
// configure pool resources
HttpClientProperties.Pool pool = properties.getPool();
if (pool.getType() == DISABLED) {
opts.disablePool();
} else if (pool.getType() == FIXED) {
PoolResources poolResources = PoolResources.fixed(pool.getName(),
pool.getMaxConnections(), pool.getAcquireTimeout());
opts.poolResources(poolResources);
} else {
PoolResources poolResources = PoolResources.elastic(pool.getName());
opts.poolResources(poolResources);
}
// configure proxy if proxy host is set.
HttpClientProperties.Proxy proxy = properties.getProxy();
if (StringUtils.hasText(proxy.getHost())) {
opts.proxy(typeSpec -> {
ClientProxyOptions.Builder builder = typeSpec
.type(ClientProxyOptions.Proxy.HTTP)
.host(proxy.getHost());
PropertyMapper map = PropertyMapper.get();
map.from(proxy::getPort)
.whenNonNull()
.to(builder::port);
map.from(proxy::getUsername)
.whenHasText()
.to(builder::username);
map.from(proxy::getPassword)
.whenHasText()
.to(password -> builder.password(s -> password));
map.from(proxy::getNonProxyHostsPattern)
.whenHasText()
.to(builder::nonProxyHosts);
return builder;
});
}
};
}
@Bean
public HttpClientProperties httpClientProperties() {
return new HttpClientProperties();
}
@Bean
public NettyRoutingFilter routingFilter(HttpClient httpClient,
ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
return new NettyRoutingFilter(httpClient, headersFilters);
}
@Bean
public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
}
@Bean
public ReactorNettyWebSocketClient reactorNettyWebSocketClient(@Qualifier("nettyClientOptions") Consumer<? super HttpClientOptions.Builder> options) {
return new ReactorNettyWebSocketClient(options);
}
}
//......
}
Spring cloud gateway uses reactor’s httpclient, which constructs options through nettyClientOptions bean. the specific configuration is HttpClientProperties
HttpClientProperties
Configuration description
{
"sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties",
"name": "spring.cloud.gateway.httpclient",
"type": "org.springframework.cloud.gateway.config.HttpClientProperties"
},
{
"sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties",
"name": "spring.cloud.gateway.httpclient.pool",
"sourceMethod": "getPool()",
"type": "org.springframework.cloud.gateway.config.HttpClientProperties$Pool"
},
{
"sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties",
"name": "spring.cloud.gateway.httpclient.proxy",
"sourceMethod": "getProxy()",
"type": "org.springframework.cloud.gateway.config.HttpClientProperties$Proxy"
},
{
"sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties",
"name": "spring.cloud.gateway.httpclient.ssl",
"sourceMethod": "getSsl()",
"type": "org.springframework.cloud.gateway.config.HttpClientProperties$Ssl"
}
You can see that the main configurations are pool, proxy and ssl
Configuration class
spring-cloud-gateway-core-2.0.0.RC1-sources.jar! /org/springframework/cloud/gateway/config/HttpClientProperties.java
@ConfigurationProperties("spring.cloud.gateway.httpclient")
public class HttpClientProperties {
/** Pool configuration for Netty HttpClient */
private Pool pool = new Pool();
/** Proxy configuration for Netty HttpClient */
private Proxy proxy = new Proxy();
/** SSL configuration for Netty HttpClient */
private Ssl ssl = new Ssl();
//......
@Override
public String toString() {
return "HttpClientProperties{" +
"pool=" + pool +
", proxy=" + proxy +
'}';
}
}
Pool
public static class Pool {
public enum PoolType { ELASTIC, FIXED, DISABLED }
/** Type of pool for HttpClient to use, defaults to ELASTIC. */
private PoolType type = PoolType.ELASTIC;
/** The channel pool map name, defaults to proxy. */
private String name = "proxy";
/** Only for type FIXED, the maximum number of connections before starting pending acquisition on existing ones. */
private Integer maxConnections = PoolResources.DEFAULT_POOL_MAX_CONNECTION;
/** Only for type FIXED, the maximum time in millis to wait for aquiring. */
private Long acquireTimeout = PoolResources.DEFAULT_POOL_ACQUIRE_TIMEOUT;
//......
@Override
public String toString() {
return "Pool{" +
"type=" + type +
", name='" + name + '\'' +
", maxConnections=" + maxConnections +
", acquireTimeout=" + acquireTimeout +
'}';
}
}
A total of the following attributes can be specified
- Spring.cloud.gateway.http client.pool.type, default is ELASTIC.
- Spring.cloud.gateway.http client.pool.name, the default is proxy.
If type is a fixed type, you can also specify the following two parameters
- The default is poolresources.default _ pool _ max _ connection.
/**
* Default max connection, if -1 will never wait to acquire before opening new
* connection in an unbounded fashion. Fallback to
* available number of processors.
*/
int DEFAULT_POOL_MAX_CONNECTION =
Integer.parseInt(System.getProperty("reactor.ipc.netty.pool.maxConnections",
"" + Math.max(Runtime.getRuntime()
.availableProcessors(), 8) * 2));
- Spring.cloud.gateway.http client.pool.acquiretimeout, default _ pool _ acquiretimeout
/**
* Default acquisition timeout before error. If -1 will never wait to
* acquire before opening new
* connection in an unbounded fashion. Fallback to
* available number of processors.
*/
long DEFAULT_POOL_ACQUIRE_TIMEOUT = Long.parseLong(System.getProperty(
"reactor.ipc.netty.pool.acquireTimeout",
"" + 45000));
Proxy
public class Proxy {
/** Hostname for proxy configuration of Netty HttpClient. */
private String host;
/** Port for proxy configuration of Netty HttpClient. */
private Integer port;
/** Username for proxy configuration of Netty HttpClient. */
private String username;
/** Password for proxy configuration of Netty HttpClient. */
private String password;
/** Regular expression (Java) for a configured list of hosts
* that should be reached directly, bypassing the proxy */
private String nonProxyHostsPattern;
//......
@Override
public String toString() {
return "Proxy{" +
"host='" + host + '\'' +
", port=" + port +
", username='" + username + '\'' +
", password='" + password + '\'' +
", nonProxyHostsPattern='" + nonProxyHostsPattern + '\'' +
'}';
}
}
The following parameters can be configured
- spring.cloud.gateway.httpclient.proxy.host
- spring.cloud.gateway.httpclient.proxy.port
- spring.cloud.gateway.httpclient.proxy.username
- spring.cloud.gateway.httpclient.proxy.password
- spring.cloud.gateway.httpclient.proxy.nonProxyHostsPattern
Ssl
public class Ssl {
/** Installs the netty InsecureTrustManagerFactory. This is insecure and not suitable for production. */
private boolean useInsecureTrustManager = false;
//TODO: support configuration of other trust manager factories
public boolean isUseInsecureTrustManager() {
return useInsecureTrustManager;
}
public void setUseInsecureTrustManager(boolean useInsecureTrustManager) {
this.useInsecureTrustManager = useInsecureTrustManager;
}
@Override
public String toString() {
return "Ssl{" +
"useInsecureTrustManager=" + useInsecureTrustManager +
'}';
}
}
It is mainly to configure the Spring.cloud.gateway.http client.ssl.use-insurance-trust-manager attribute. If it is set to true, the INSecure Trustmanagerfactory.instance will be used.
netty-handler-4.1.23.Final-sources.jar! /io/netty/handler/ssl/util/InsecureTrustManagerFactory.java
/**
* An insecure {@link TrustManagerFactory} that trusts all X.509 certificates without any verification.
* <p>
* <strong>NOTE:</strong>
* Never use this {@link TrustManagerFactory} in production.
* It is purely for testing purposes, and thus it is very insecure.
* </p>
*/
public final class InsecureTrustManagerFactory extends SimpleTrustManagerFactory {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(InsecureTrustManagerFactory.class);
public static final TrustManagerFactory INSTANCE = new InsecureTrustManagerFactory();
private static final TrustManager tm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String s) {
logger.debug("Accepting a client certificate: " + chain[0].getSubjectDN());
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String s) {
logger.debug("Accepting a server certificate: " + chain[0].getSubjectDN());
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return EmptyArrays.EMPTY_X509_CERTIFICATES;
}
};
private InsecureTrustManagerFactory() { }
@Override
protected void engineInit(KeyStore keyStore) throws Exception { }
@Override
protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws Exception { }
@Override
protected TrustManager[] engineGetTrustManagers() {
return new TrustManager[] { tm };
}
}
Summary
The bottom layer of spring cloud gateway uses reactor’s httpclient, and relevant options can be specified through the configuration of spring.cloud.gateway.http client prefix. There are three main categories: pool, proxy and ssl. The default type of pool is elastic. if it is fixed, you can also specify maxConnections and acquireTimeout parameters.