From 52fedb2bb4da081a9c1750f0fea214b50a0db96b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 23 Feb 2021 13:22:18 +0100 Subject: [PATCH] Add support for InfluxDB 2.x Closes gh-25891 --- .../spring-boot-autoconfigure/build.gradle | 1 + .../influx/InfluxDbAutoConfiguration.java | 54 ++++++++++++++----- ...nfluxDbClientOptionsBuilderCustomizer.java | 39 ++++++++++++++ .../InfluxDbAutoConfigurationTests.java | 51 ++++++++++++++++++ .../spring-boot-dependencies/build.gradle | 7 +++ .../src/docs/asciidoc/features/nosql.adoc | 4 +- 6 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbClientOptionsBuilderCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index 74a370fb324..77111a9d6b9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -23,6 +23,7 @@ dependencies { optional("com.hazelcast:hazelcast") optional("com.hazelcast:hazelcast-spring") optional("com.h2database:h2") + optional("com.influxdb:influxdb-client-java") optional("com.nimbusds:oauth2-oidc-sdk") optional("com.oracle.database.jdbc:ojdbc8") optional("com.oracle.database.jdbc:ucp") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfiguration.java index e1cf2ec7871..2b1cc5d6c54 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfiguration.java @@ -16,6 +16,10 @@ package org.springframework.boot.autoconfigure.influx; +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.InfluxDBClientFactory; +import com.influxdb.client.InfluxDBClientOptions; +import com.influxdb.client.InfluxDBClientOptions.Builder; import okhttp3.OkHttpClient; import org.influxdb.InfluxDB; import org.influxdb.impl.InfluxDBImpl; @@ -28,6 +32,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for InfluxDB. @@ -38,21 +43,10 @@ import org.springframework.context.annotation.Configuration; * @since 2.0.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass(InfluxDB.class) +@ConditionalOnProperty("spring.influx.url") @EnableConfigurationProperties(InfluxDbProperties.class) public class InfluxDbAutoConfiguration { - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty("spring.influx.url") - public InfluxDB influxDb(InfluxDbProperties properties, ObjectProvider builder, - ObjectProvider customizers) { - InfluxDB influxDb = new InfluxDBImpl(properties.getUrl(), properties.getUser(), properties.getPassword(), - determineBuilder(builder.getIfAvailable())); - customizers.orderedStream().forEach((customizer) -> customizer.customize(influxDb)); - return influxDb; - } - private static OkHttpClient.Builder determineBuilder(InfluxDbOkHttpClientBuilderProvider builder) { if (builder != null) { return builder.get(); @@ -60,4 +54,40 @@ public class InfluxDbAutoConfiguration { return new OkHttpClient.Builder(); } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(InfluxDB.class) + static class Influx1xConfiguration { + + @Bean + @ConditionalOnMissingBean + InfluxDB influxDb(InfluxDbProperties properties, ObjectProvider builder, + ObjectProvider customizers) { + InfluxDB influxDb = new InfluxDBImpl(properties.getUrl(), properties.getUser(), properties.getPassword(), + determineBuilder(builder.getIfAvailable())); + customizers.orderedStream().forEach((customizer) -> customizer.customize(influxDb)); + return influxDb; + } + + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(InfluxDBClient.class) + static class Influx2xConfiguration { + + @Bean + @ConditionalOnMissingBean + InfluxDBClient influxDbClient(InfluxDbProperties properties, + ObjectProvider httpClientBuilder, + ObjectProvider customizers) { + Builder builder = InfluxDBClientOptions.builder().url(properties.getUrl()); + if (StringUtils.hasText(properties.getUser()) && StringUtils.hasText(properties.getPassword())) { + builder.authenticate(properties.getUser(), properties.getPassword().toCharArray()); + } + builder.okHttpClient(determineBuilder(httpClientBuilder.getIfAvailable())); + customizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + return InfluxDBClientFactory.create(builder.build()); + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbClientOptionsBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbClientOptionsBuilderCustomizer.java new file mode 100644 index 00000000000..d1cfb78c2fd --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/influx/InfluxDbClientOptionsBuilderCustomizer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.influx; + +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.InfluxDBClientOptions; + +/** + * Callback interface that can be implemented by beans wishing to further customize + * {@link InfluxDBClientOptions} used to configure an {@link InfluxDBClient} whilst + * retaining default auto-configuration. + * + * @author Stephane Nicoll + * @since 2.6.0 + */ +@FunctionalInterface +public interface InfluxDbClientOptionsBuilderCustomizer { + + /** + * Customize the {@link InfluxDBClientOptions}. + * @param builder the influxDB client options builder to customize + */ + void customize(InfluxDBClientOptions.Builder builder); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfigurationTests.java index 34033cd6695..00c1377d3a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/influx/InfluxDbAutoConfigurationTests.java @@ -17,8 +17,12 @@ package org.springframework.boot.autoconfigure.influx; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.InfluxDBClientOptions; import okhttp3.OkHttpClient; +import org.assertj.core.api.InstanceOfAssertFactories; import org.influxdb.InfluxDB; import org.junit.jupiter.api.Test; import retrofit2.Retrofit; @@ -26,6 +30,7 @@ import retrofit2.Retrofit; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.util.ReflectionTestUtils; @@ -86,6 +91,42 @@ class InfluxDbAutoConfigurationTests { }); } + @Test + void influxDbClientRequiresUrl() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(InfluxDBClient.class)); + } + + @Test + void influxDbClientCanBeCustomized() { + this.contextRunner + .withPropertyValues("spring.influx.url=http://localhost", "spring.influx.user=user", + "spring.influx.password=password") + .run((context) -> assertThat(context).hasSingleBean(InfluxDBClient.class)); + } + + @Test + void influxDbClientCanBeCreatedWithoutCredentials() { + this.contextRunner.withPropertyValues("spring.influx.url=http://localhost").run(assertInfluxDbClientOptions( + (options) -> assertThat(options.getOkHttpClient().build().readTimeoutMillis()).isEqualTo(10000))); + } + + @Test + void influxDbClientWithOkHttpClientBuilderProvider() { + this.contextRunner.withUserConfiguration(CustomOkHttpClientBuilderProviderConfig.class) + .withPropertyValues("spring.influx.url=http://localhost") + .run(assertInfluxDbClientOptions( + (options) -> assertThat(options.getOkHttpClient().build().readTimeoutMillis()) + .isEqualTo(40000))); + } + + @Test + void influxDbClientWithCustomizer() { + this.contextRunner + .withBean(InfluxDbClientOptionsBuilderCustomizer.class, () -> (options) -> options.org("my_org")) + .withPropertyValues("spring.influx.url=http://localhost") + .run(assertInfluxDbClientOptions((options) -> assertThat(options.getOrg()).isEqualTo("my_org"))); + } + private int getReadTimeoutProperty(AssertableApplicationContext context) { InfluxDB influxDb = context.getBean(InfluxDB.class); Retrofit retrofit = (Retrofit) ReflectionTestUtils.getField(influxDb, "retrofit"); @@ -93,6 +134,16 @@ class InfluxDbAutoConfigurationTests { return callFactory.readTimeoutMillis(); } + private ContextConsumer assertInfluxDbClientOptions( + Consumer options) { + return (context) -> { + assertThat(context).hasSingleBean(InfluxDBClient.class); + assertThat(context).getBean(InfluxDBClient.class) + .extracting("options", InstanceOfAssertFactories.type(InfluxDBClientOptions.class)) + .satisfies(options); + }; + } + @Configuration(proxyBeanMethods = false) static class CustomOkHttpClientBuilderProviderConfig { diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 8d4fa1c9593..0c8d0040161 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -520,6 +520,13 @@ bom { ] } } + library("InfluxDB Client Java", "2.3.0") { + group("com.influxdb") { + modules = [ + "influxdb-client-java" + ] + } + } library("InfluxDB Java", "2.21") { group("org.influxdb") { modules = [ diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc index 53d8601fc7d..916cf121cd0 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/nosql.adoc @@ -631,7 +631,7 @@ https://www.influxdata.com/[InfluxDB] is an open-source time series database opt [[features.nosql.influxdb.connecting]] ==== Connecting to InfluxDB -Spring Boot auto-configures an `InfluxDB` instance, provided the `influxdb-java` client is on the classpath and the URL of the database is set, as shown in the following example: +Spring Boot auto-configures a client instance, provided that either `influxdb-java` (Influx 1.x) or `influxdb-client-java` (Influx 2.x) is on the classpath and the URL of the database is set, as shown in the following example: [source,yaml,indent=0,subs="verbatim",configprops,configblocks] ---- @@ -645,4 +645,4 @@ If the connection to InfluxDB requires a user and password, you can set the `spr InfluxDB relies on OkHttp. If you need to tune the http client `InfluxDB` uses behind the scenes, you can register an `InfluxDbOkHttpClientBuilderProvider` bean. -If you need more control over the configuration, consider registering an `InfluxDbCustomizer` bean. +If you need more control over the configuration, consider registering an `InfluxDbCustomizer` (Influx 1.x), or an `InfluxDbClientOptionsBuilderCustomizer` (Influx 2.x) bean.