序
本文主要研究下spring cloud gateway的NettyConfiguration
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> 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使用的是reactor的httpclient,其通过nettyClientOptions这个bean来进行构造options,具体的配置是HttpClientProperties
HttpClientProperties
配置说明
{
"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"
}
可以看到主要是pool、proxy、ssl这几个配置
配置类
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 +
'}';
}
}
一共可以指定如下几个属性
- spring.cloud.gateway.httpclient.pool.type,默认是ELASTIC
- spring.cloud.gateway.httpclient.pool.name,默认是proxy
如果type是fixed类型,还可以指定如下两个参数
- spring.cloud.gateway.httpclient.pool.maxConnections,默认是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.httpclient.pool.acquireTimeout,默认是PoolResources.DEFAULT_POOL_ACQUIRE_TIMEOUT
/**
* 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 + '\'' +
'}';
}
}
可以配置如下几个参数
- 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 +
'}';
}
}
主要是配置spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager属性,设置为true的话,则会使用InsecureTrustManagerFactory.INSTANCE
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.
*
* NOTE:
* Never use this {@link TrustManagerFactory} in production.
* It is purely for testing purposes, and thus it is very insecure.
*
*/
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 };
}
}
小结
spring cloud gateway底层使用的是reactor的httpclient,可以通过spring.cloud.gateway.httpclient前缀的配置来指定相关options。主要分pool、proxy、ssl三大类。其中pool默认的type是elastic,如果是fixed的话,还可以指定maxConnections及acquireTimeout参数。
doc
- Part XV. Spring Cloud Gateway