Talk about springboot jest autoconfigure

  jest

Order

This article mainly studies springboot jest autoconfigure.

JestProperties

spring-boot-autoconfigure-2.1.4.RELEASE-sources.jar! /org/springframework/boot/autoconfigure/elasticsearch/jest/JestProperties.java

@ConfigurationProperties(prefix = "spring.elasticsearch.jest")
public class JestProperties {

    /**
     * Comma-separated list of the Elasticsearch instances to use.
     */
    private List<String> uris = new ArrayList<>(
            Collections.singletonList("http://localhost:9200"));

    /**
     * Login username.
     */
    private String username;

    /**
     * Login password.
     */
    private String password;

    /**
     * Whether to enable connection requests from multiple execution threads.
     */
    private boolean multiThreaded = true;

    /**
     * Connection timeout.
     */
    private Duration connectionTimeout = Duration.ofSeconds(3);

    /**
     * Read timeout.
     */
    private Duration readTimeout = Duration.ofSeconds(3);

    /**
     * Proxy settings.
     */
    private final Proxy proxy = new Proxy();

    //......

    public static class Proxy {

        /**
         * Proxy host the HTTP client should use.
         */
        private String host;

        /**
         * Proxy port the HTTP client should use.
         */
        private Integer port;

        public String getHost() {
            return this.host;
        }

        public void setHost(String host) {
            this.host = host;
        }

        public Integer getPort() {
            return this.port;
        }

        public void setPort(Integer port) {
            this.port = port;
        }

    }
}
  • JestProperties provides uris, username, password, multiThreaded (Default true)、connectionTimeout(Default 3s)、readTimeout(Default 3s), proxy configuration

JestAutoConfiguration

spring-boot-autoconfigure-2.1.4.RELEASE-sources.jar! /org/springframework/boot/autoconfigure/elasticsearch/jest/JestAutoConfiguration.java

@Configuration
@ConditionalOnClass(JestClient.class)
@EnableConfigurationProperties(JestProperties.class)
@AutoConfigureAfter(GsonAutoConfiguration.class)
public class JestAutoConfiguration {

    private final JestProperties properties;

    private final ObjectProvider<Gson> gsonProvider;

    private final ObjectProvider<HttpClientConfigBuilderCustomizer> builderCustomizers;

    public JestAutoConfiguration(JestProperties properties, ObjectProvider<Gson> gson,
            ObjectProvider<HttpClientConfigBuilderCustomizer> builderCustomizers) {
        this.properties = properties;
        this.gsonProvider = gson;
        this.builderCustomizers = builderCustomizers;
    }

    @Bean(destroyMethod = "shutdownClient")
    @ConditionalOnMissingBean
    public JestClient jestClient() {
        JestClientFactory factory = new JestClientFactory();
        factory.setHttpClientConfig(createHttpClientConfig());
        return factory.getObject();
    }

    protected HttpClientConfig createHttpClientConfig() {
        HttpClientConfig.Builder builder = new HttpClientConfig.Builder(
                this.properties.getUris());
        PropertyMapper map = PropertyMapper.get();
        map.from(this.properties::getUsername).whenHasText().to((username) -> builder
                .defaultCredentials(username, this.properties.getPassword()));
        Proxy proxy = this.properties.getProxy();
        map.from(proxy::getHost).whenHasText().to((host) -> {
            Assert.notNull(proxy.getPort(), "Proxy port must not be null");
            builder.proxy(new HttpHost(host, proxy.getPort()));
        });
        map.from(this.gsonProvider::getIfUnique).whenNonNull().to(builder::gson);
        map.from(this.properties::isMultiThreaded).to(builder::multiThreaded);
        map.from(this.properties::getConnectionTimeout).whenNonNull()
                .asInt(Duration::toMillis).to(builder::connTimeout);
        map.from(this.properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
                .to(builder::readTimeout);
        customize(builder);
        return builder.build();
    }

    private void customize(HttpClientConfig.Builder builder) {
        this.builderCustomizers.orderedStream()
                .forEach((customizer) -> customizer.customize(builder));
    }

}
  • Without jestClient’s bean, JestAutoConfiguration creates HttpClientConfig through JestProperties, and then uses JestClientFactory to create JestClient while marking its destroyMethod as shutdownClient method.

JestClientFactory

jest-6.3.1-sources.jar! /io/searchbox/client/JestClientFactory.java

public class JestClientFactory {

    final static Logger log = LoggerFactory.getLogger(JestClientFactory.class);
    private HttpClientConfig httpClientConfig;

    public JestClient getObject() {
        JestHttpClient client = new JestHttpClient();

        if (httpClientConfig == null) {
            log.debug("There is no configuration to create http client. Going to create simple client with default values");
            httpClientConfig = new HttpClientConfig.Builder("http://localhost:9200").build();
        }

        client.setRequestCompressionEnabled(httpClientConfig.isRequestCompressionEnabled());
        client.setServers(httpClientConfig.getServerList());
        final HttpClientConnectionManager connectionManager = getConnectionManager();
        final NHttpClientConnectionManager asyncConnectionManager = getAsyncConnectionManager();
        client.setHttpClient(createHttpClient(connectionManager));
        client.setAsyncClient(createAsyncHttpClient(asyncConnectionManager));

        // set custom gson instance
        Gson gson = httpClientConfig.getGson();
        if (gson == null) {
            log.info("Using default GSON instance");
        } else {
            log.info("Using custom GSON instance");
            client.setGson(gson);
        }

        // set discovery (should be set after setting the httpClient on jestClient)
        if (httpClientConfig.isDiscoveryEnabled()) {
            log.info("Node Discovery enabled...");
            if (!Strings.isNullOrEmpty(httpClientConfig.getDiscoveryFilter())) {
                log.info("Node Discovery filtering nodes on \"{}\"", httpClientConfig.getDiscoveryFilter());
            }
            NodeChecker nodeChecker = createNodeChecker(client, httpClientConfig);
            client.setNodeChecker(nodeChecker);
            nodeChecker.startAsync();
            nodeChecker.awaitRunning();
        } else {
            log.info("Node Discovery disabled...");
        }

        // schedule idle connection reaping if configured
        if (httpClientConfig.getMaxConnectionIdleTime() > 0) {
            log.info("Idle connection reaping enabled...");

            IdleConnectionReaper reaper = new IdleConnectionReaper(httpClientConfig, new HttpReapableConnectionManager(connectionManager, asyncConnectionManager));
            client.setIdleConnectionReaper(reaper);
            reaper.startAsync();
            reaper.awaitRunning();
        } else {
            log.info("Idle connection reaping disabled...");
        }

        Set<HttpHost> preemptiveAuthTargetHosts = httpClientConfig.getPreemptiveAuthTargetHosts();
        if (!preemptiveAuthTargetHosts.isEmpty()) {
            log.info("Authentication cache set for preemptive authentication");
            client.setHttpClientContextTemplate(createPreemptiveAuthContext(preemptiveAuthTargetHosts));
        }

        client.setElasticsearchVersion(httpClientConfig.getElasticsearchVersion());

        return client;
    }

    public void setHttpClientConfig(HttpClientConfig httpClientConfig) {
        this.httpClientConfig = httpClientConfig;
    }

    //......

}
  • The getObject method of JestClientFactory first creates JestHttpClient, and then sets up HttpClient and AsyncClient.
  • If isDiscoveryEnabled is true, NodeChecker will be created and nodeddiscovery will be executed.
  • If maxConnectionIdleTime is greater than 0, IdleConnectionReaper will be created for Idle connection reaping.

Summary

  • JestProperties provides uris, username, password, multiThreaded (Default true)、connectionTimeout(Default 3s)、readTimeout(Default 3s), proxy configuration
  • Without jestClient’s bean, JestAutoConfiguration creates HttpClientConfig through JestProperties, and then uses JestClientFactory to create JestClient while marking its destroyMethod as shutdownClient method.
  • The getObject method of JestClientFactory first creates JestHttpClient, and then sets up HttpClient and AsyncClient; ; If isDiscoveryEnabled is true, NodeChecker will be created and NodeDiscovery will be executed; If maxConnectionIdleTime is greater than 0, IdleConnectionReaper will be created for Idle connection reaping.

doc