Merge branch '2.3.x'

Closes gh-22874
pull/22898/head
Stephane Nicoll 4 years ago
commit 5bd69fcd61

@ -28,6 +28,7 @@ import org.springframework.util.Assert;
* @author Phillip Webb * @author Phillip Webb
* @author Eddú Meléndez * @author Eddú Meléndez
*/ */
@SuppressWarnings("deprecation")
final class CacheConfigurations { final class CacheConfigurations {
private static final Map<CacheType, Class<?>> MAPPINGS; private static final Map<CacheType, Class<?>> MAPPINGS;

@ -21,6 +21,7 @@ import java.util.List;
import com.couchbase.client.java.Cluster; import com.couchbase.client.java.Cluster;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.cache.CacheProperties.Couchbase; import org.springframework.boot.autoconfigure.cache.CacheProperties.Couchbase;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -39,16 +40,20 @@ import org.springframework.util.ObjectUtils;
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 1.4.0 * @since 1.4.0
* @deprecated since 2.3.3 as this class is not intended for public use. It will be made
* package-private in a future release
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class }) @ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class })
@ConditionalOnMissingBean(CacheManager.class) @ConditionalOnMissingBean(CacheManager.class)
@ConditionalOnSingleCandidate(CouchbaseClientFactory.class) @ConditionalOnSingleCandidate(CouchbaseClientFactory.class)
@Conditional(CacheCondition.class) @Conditional(CacheCondition.class)
@Deprecated
public class CouchbaseCacheConfiguration { public class CouchbaseCacheConfiguration {
@Bean @Bean
public CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers, public CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,
ObjectProvider<CouchbaseCacheManagerBuilderCustomizer> couchbaseCacheManagerBuilderCustomizers,
CouchbaseClientFactory clientFactory) { CouchbaseClientFactory clientFactory) {
List<String> cacheNames = cacheProperties.getCacheNames(); List<String> cacheNames = cacheProperties.getCacheNames();
CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory); CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory);
@ -62,6 +67,7 @@ public class CouchbaseCacheConfiguration {
if (!ObjectUtils.isEmpty(cacheNames)) { if (!ObjectUtils.isEmpty(cacheNames)) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
} }
couchbaseCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
CouchbaseCacheManager cacheManager = builder.build(); CouchbaseCacheManager cacheManager = builder.build();
return customizers.customize(cacheManager); return customizers.customize(cacheManager);
} }

@ -0,0 +1,39 @@
/*
* Copyright 2012-2019 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.cache;
import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;
/**
* Callback interface that can be implemented by beans wishing to customize the
* {@link CouchbaseCacheManagerBuilder} before it is used to build the auto-configured
* {@link CouchbaseCacheManager}.
*
* @author Stephane Nicoll
* @since 2.3.3
*/
@FunctionalInterface
public interface CouchbaseCacheManagerBuilderCustomizer {
/**
* Customize the {@link CouchbaseCacheManagerBuilder}.
* @param builder the builder to customize
*/
void customize(CouchbaseCacheManagerBuilder builder);
}

@ -65,6 +65,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.data.couchbase.CouchbaseClientFactory; import org.springframework.data.couchbase.CouchbaseClientFactory;
import org.springframework.data.couchbase.cache.CouchbaseCache; import org.springframework.data.couchbase.cache.CouchbaseCache;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;
import org.springframework.data.couchbase.cache.CouchbaseCacheManager; import org.springframework.data.couchbase.cache.CouchbaseCacheManager;
import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
@ -196,7 +197,7 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
@Test @Test
void couchbaseCacheExplicit() { void couchbaseCacheExplicit() {
this.contextRunner.withUserConfiguration(CouchbaseCacheConfiguration.class) this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)
.withPropertyValues("spring.cache.type=couchbase").run((context) -> { .withPropertyValues("spring.cache.type=couchbase").run((context) -> {
CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class); CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);
assertThat(cacheManager.getCacheNames()).isEmpty(); assertThat(cacheManager.getCacheNames()).isEmpty();
@ -205,14 +206,14 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
@Test @Test
void couchbaseCacheWithCustomizers() { void couchbaseCacheWithCustomizers() {
this.contextRunner.withUserConfiguration(CouchbaseCacheAndCustomizersConfiguration.class) this.contextRunner.withUserConfiguration(CouchbaseWithCustomizersConfiguration.class)
.withPropertyValues("spring.cache.type=couchbase") .withPropertyValues("spring.cache.type=couchbase")
.run(verifyCustomizers("allCacheManagerCustomizer", "couchbaseCacheManagerCustomizer")); .run(verifyCustomizers("allCacheManagerCustomizer", "couchbaseCacheManagerCustomizer"));
} }
@Test @Test
void couchbaseCacheExplicitWithCaches() { void couchbaseCacheExplicitWithCaches() {
this.contextRunner.withUserConfiguration(CouchbaseCacheConfiguration.class) this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)
.withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames[0]=foo", .withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames[0]=foo",
"spring.cache.cacheNames[1]=bar") "spring.cache.cacheNames[1]=bar")
.run((context) -> { .run((context) -> {
@ -226,7 +227,7 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
@Test @Test
void couchbaseCacheExplicitWithTtl() { void couchbaseCacheExplicitWithTtl() {
this.contextRunner.withUserConfiguration(CouchbaseCacheConfiguration.class) this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)
.withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames=foo,bar", .withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames=foo,bar",
"spring.cache.couchbase.expiration=2000") "spring.cache.couchbase.expiration=2000")
.run((context) -> { .run((context) -> {
@ -238,6 +239,20 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
}); });
} }
@Test
void couchbaseCacheWithCouchbaseCacheManagerBuilderCustomizer() {
this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)
.withPropertyValues("spring.cache.type=couchbase", "spring.cache.couchbase.expiration=15s")
.withBean(CouchbaseCacheManagerBuilderCustomizer.class, () -> (builder) -> builder.cacheDefaults(
CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry(java.time.Duration.ofSeconds(10))))
.run((context) -> {
CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);
CouchbaseCacheConfiguration couchbaseCacheConfiguration = getDefaultCouchbaseCacheConfiguration(
cacheManager);
assertThat(couchbaseCacheConfiguration.getExpiry()).isEqualTo(java.time.Duration.ofSeconds(10));
});
}
@Test @Test
void redisCacheExplicit() { void redisCacheExplicit() {
this.contextRunner.withUserConfiguration(RedisConfiguration.class) this.contextRunner.withUserConfiguration(RedisConfiguration.class)
@ -668,6 +683,10 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
assertThat(((CaffeineCache) foo).getNativeCache().stats().missCount()).isEqualTo(1L); assertThat(((CaffeineCache) foo).getNativeCache().stats().missCount()).isEqualTo(1L);
} }
private CouchbaseCacheConfiguration getDefaultCouchbaseCacheConfiguration(CouchbaseCacheManager cacheManager) {
return (CouchbaseCacheConfiguration) ReflectionTestUtils.getField(cacheManager, "defaultCacheConfig");
}
private RedisCacheConfiguration getDefaultRedisCacheConfiguration(RedisCacheManager cacheManager) { private RedisCacheConfiguration getDefaultRedisCacheConfiguration(RedisCacheManager cacheManager) {
return (RedisCacheConfiguration) ReflectionTestUtils.getField(cacheManager, "defaultCacheConfig"); return (RedisCacheConfiguration) ReflectionTestUtils.getField(cacheManager, "defaultCacheConfig");
} }
@ -721,7 +740,7 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableCaching @EnableCaching
static class CouchbaseCacheConfiguration { static class CouchbaseConfiguration {
@Bean @Bean
CouchbaseClientFactory couchbaseClientFactory() { CouchbaseClientFactory couchbaseClientFactory() {
@ -731,8 +750,8 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@Import({ CouchbaseCacheConfiguration.class, CacheManagerCustomizersConfiguration.class }) @Import({ CouchbaseConfiguration.class, CacheManagerCustomizersConfiguration.class })
static class CouchbaseCacheAndCustomizersConfiguration { static class CouchbaseWithCustomizersConfiguration {
} }

@ -80,6 +80,7 @@ dependencies {
implementation("org.springframework:spring-test") implementation("org.springframework:spring-test")
implementation("org.springframework:spring-web") implementation("org.springframework:spring-web")
implementation("org.springframework:spring-webflux") implementation("org.springframework:spring-webflux")
implementation("org.springframework.data:spring-data-couchbase")
implementation("org.springframework.data:spring-data-redis") implementation("org.springframework.data:spring-data-redis")
implementation("org.springframework.data:spring-data-r2dbc") implementation("org.springframework.data:spring-data-r2dbc")
implementation("org.springframework.kafka:spring-kafka") implementation("org.springframework.kafka:spring-kafka")

@ -5163,49 +5163,24 @@ See https://github.com/infinispan/infinispan-spring-boot[Infinispan's documentat
[[boot-features-caching-provider-couchbase]] [[boot-features-caching-provider-couchbase]]
==== Couchbase ==== Couchbase
If the https://www.couchbase.com/[Couchbase] Java client and the `couchbase-spring-cache` implementation are available and Couchbase is <<boot-features-couchbase,configured>>, a `CouchbaseCacheManager` is auto-configured. If Spring Data Couchbase is available and Couchbase is <<boot-features-couchbase,configured>>, a `CouchbaseCacheManager` is auto-configured.
It is also possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property. It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.couchbase.*` properties.
These caches operate on the `Bucket` that was auto-configured. For instance, the following configuration creates `cache1` and `cache2` caches with an entry _expiration_ of 10 minutes:
You can _also_ create additional caches on another `Bucket` by using the customizer.
Assume you need two caches (`cache1` and `cache2`) on the "main" `Bucket` and one (`cache3`) cache with a custom time to live of 2 seconds on the "`another`" `Bucket`.
You can create the first two caches through configuration, as follows:
[source,properties,indent=0,configprops] [source,properties,indent=0,configprops]
---- ----
spring.cache.cache-names=cache1,cache2 spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
---- ----
Then you can define a `@Configuration` class to configure the extra `Bucket` and the `cache3` cache, as follows: If you need more control over the configuration, consider registering a `CouchbaseCacheManagerBuilderCustomizer` bean.
The following example shows a customizer that configures a specific entry expiration for `cache1` and `cache2`:
[source,java,indent=0] [source,java,indent=0]
---- ----
@Configuration(proxyBeanMethods = false) include::{code-examples}/cache/CouchbaseCacheManagerCustomizationExample.java[tag=configuration]
public class CouchbaseCacheConfiguration {
private final Cluster cluster;
public CouchbaseCacheConfiguration(Cluster cluster) {
this.cluster = cluster;
}
@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
}
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
return c -> {
c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
};
}
}
---- ----
This sample configuration reuses the `Cluster` that was created through auto-configuration.
[[boot-features-caching-provider-redis]] [[boot-features-caching-provider-redis]]

@ -0,0 +1,47 @@
/*
* Copyright 2012-2020 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.docs.cache;
import java.time.Duration;
import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;
/**
* An example how to customize {@code CouchbaseCacheManagerBuilder} via
* {@code CouchbaseCacheManagerBuilderCustomizer}.
*
* @author Dmytro Nosan
*/
@Configuration(proxyBeanMethods = false)
public class CouchbaseCacheManagerCustomizationExample {
// tag::configuration[]
@Bean
public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheConfiguration("cache1",
CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))
.withCacheConfiguration("cache2",
CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));
}
// end::configuration[]
}
Loading…
Cancel
Save