聊聊spring cloud gateway的NettyConfiguration

本文主要研究下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<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使用的是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.
 * <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 };
    }
}

小结

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

原文发布于微信公众号 - 码匠的流水账(geek_luandun)

原文发表时间:2018-06-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码匠的流水账

聊聊spring-data-redis的连接池的校验

spring-data-redis/2.0.10.RELEASE/spring-data-redis-2.0.10.RELEASE-sources.jar!/o...

70910
来自专栏difcareer的技术笔记

dextra DEX/ODEX/ART/OAT分析工具

27930
来自专栏10km的专栏

jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定

需求说明 如下是一个简单的测试对话框,我们希望当”起始日期”按钮为勾选时,数据对象dataBean的date属性为日期组件DateTime选择的值,否则为nul...

25090
来自专栏小灰灰

利用Crypto++实现RSA加密算法

之前做一个项目用到crypto++加密库,可以从官网下载对应的源码,其中有一个test.c文件,详细的演示了各种加密算法的使用方法,因此,在其基础上,我将ae...

47870
来自专栏码匠的流水账

聊聊hystrix的timeout处理

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/AbstractCommand.java

22120
来自专栏函数式编程语言及工具

SDP(2):ScalikeJDBC-Connection Pool Configuration

  scalikeJDBC可以通过配置文件来设置连接池及全局系统参数。对配置文件的解析是通过TypesafeConfig工具库实现的。默认加载classpath...

36240
来自专栏拂晓风起

jQuery 和 json 简单例子(注意callback函数的处理!!) (servlet返回json,jquery更新,java json)

13330
来自专栏码匠的流水账

聊聊sentinel的FlowSlot

com/alibaba/csp/sentinel/slots/block/flow/FlowSlot.java

17210
来自专栏码匠的流水账

聊聊rocketmq的PushConsumerImpl

io/openmessaging/rocketmq/consumer/PushConsumerImpl.java

20020
来自专栏码匠的流水账

tomcat如何关闭response的outputStream

在写文件下载的时候,遇到了一个问题,就是这个ServletOutputStream到底要不要自己flush以及close。这里以tomcat容易为例,解读一下。

16210

扫码关注云+社区

领取腾讯云代金券