diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index f2579c57230..9951e96cb10 100755
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -35,6 +35,11 @@
transactions-jta
true
+
+ com.couchbase.client
+ couchbase-spring-cache
+ true
+
com.fasterxml.jackson.core
jackson-databind
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java
index 8530bf48c27..f85244bfa2a 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java
@@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.Cache
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.EntityManagerFactoryDependsOnPostProcessor;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
@@ -64,7 +65,8 @@ import org.springframework.util.Assert;
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
-@AutoConfigureAfter({ HazelcastAutoConfiguration.class, RedisAutoConfiguration.class })
+@AutoConfigureAfter({CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
+ RedisAutoConfiguration.class })
@Import({ CacheManagerCustomizers.class, CacheConfigurationImportSelector.class })
public class CacheAutoConfiguration {
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java
index 5245b0c7d20..b5d57911401 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java
@@ -42,6 +42,7 @@ final class CacheConfigurations {
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
+ mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
mappings.put(CacheType.GUAVA, GuavaCacheConfiguration.class);
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java
index 84be9062402..df7bdf5e955 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheProperties.java
@@ -46,6 +46,8 @@ public class CacheProperties {
private final Caffeine caffeine = new Caffeine();
+ private final Couchbase couchbase = new Couchbase();
+
private final EhCache ehcache = new EhCache();
private final Hazelcast hazelcast = new Hazelcast();
@@ -76,6 +78,10 @@ public class CacheProperties {
return this.caffeine;
}
+ public Couchbase getCouchbase() {
+ return this.couchbase;
+ }
+
public EhCache getEhcache() {
return this.ehcache;
}
@@ -133,6 +139,26 @@ public class CacheProperties {
}
+ /**
+ * Couchbase specific cache properties.
+ */
+ public static class Couchbase {
+
+ /**
+ * Entry expiration in milliseconds. By default the entries never expire.
+ */
+ private int expiration;
+
+ public int getExpiration() {
+ return this.expiration;
+ }
+
+ public void setExpiration(int expiration) {
+ this.expiration = expiration;
+ }
+
+ }
+
/**
* EhCache specific cache properties.
*/
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java
index 5277c1fc471..0399777eecf 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java
@@ -51,6 +51,11 @@ public enum CacheType {
*/
INFINISPAN,
+ /**
+ * Couchbase backed caching.
+ */
+ COUCHBASE,
+
/**
* Redis backed caching.
*/
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java
new file mode 100644
index 00000000000..202c8df53dd
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012-2016 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
+ *
+ * http://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 java.util.List;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.spring.cache.CacheBuilder;
+import com.couchbase.client.spring.cache.CouchbaseCacheManager;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
+import org.springframework.cache.CacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Couchbase cache configuration.
+ *
+ * @author Stephane Nicoll
+ * @since 1.4.0
+ */
+@Configuration
+@ConditionalOnClass({Bucket.class, CouchbaseCacheManager.class})
+@ConditionalOnMissingBean(CacheManager.class)
+@ConditionalOnSingleCandidate(Bucket.class)
+@Conditional(CacheCondition.class)
+public class CouchbaseCacheConfiguration {
+
+ private final CacheProperties cacheProperties;
+
+ private final CacheManagerCustomizers customizers;
+
+ private final Bucket bucket;
+
+ public CouchbaseCacheConfiguration(CacheProperties cacheProperties,
+ CacheManagerCustomizers customizers, Bucket bucket) {
+ this.cacheProperties = cacheProperties;
+ this.customizers = customizers;
+ this.bucket = bucket;
+ }
+
+ @Bean
+ public CouchbaseCacheManager cacheManager() {
+ List cacheNames = this.cacheProperties.getCacheNames();
+ CouchbaseCacheManager cacheManager = new CouchbaseCacheManager(
+ CacheBuilder.newInstance(this.bucket)
+ .withExpirationInMillis(this.cacheProperties.getCouchbase().getExpiration()),
+ cacheNames.toArray(new String[cacheNames.size()]));
+ return this.customizers.customize(cacheManager);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java
index b87b7d85d65..34d928adcec 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java
@@ -30,6 +30,10 @@ import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.bucket.BucketManager;
+import com.couchbase.client.spring.cache.CouchbaseCache;
+import com.couchbase.client.spring.cache.CouchbaseCacheManager;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import com.google.common.cache.CacheBuilder;
@@ -207,6 +211,43 @@ public class CacheAutoConfigurationTests {
assertThat(cacheManager.getCacheNames()).hasSize(2);
}
+ @Test
+ public void couchbaseCacheExplicit() {
+ load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase");
+ CouchbaseCacheManager cacheManager = validateCacheManager(CouchbaseCacheManager.class);
+ assertThat(cacheManager.getCacheNames()).isEmpty();
+ }
+
+ @Test
+ public void couchbaseCacheWithCustomizers() {
+ testCustomizers(CouchbaseCacheAndCustomizersConfiguration.class, "couchbase",
+ "allCacheManagerCustomizer", "couchbaseCacheManagerCustomizer");
+ }
+
+ @Test
+ public void couchbaseCacheExplicitWithCaches() {
+ load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase",
+ "spring.cache.cacheNames[0]=foo", "spring.cache.cacheNames[1]=bar");
+ CouchbaseCacheManager cacheManager = validateCacheManager(CouchbaseCacheManager.class);
+ assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
+ Cache cache = cacheManager.getCache("foo");
+ assertThat(cache).isInstanceOf(CouchbaseCache.class);
+ assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(0);
+ assertThat(((CouchbaseCache) cache).getNativeCache()).isEqualTo(this.context.getBean("bucket"));
+ }
+
+ @Test
+ public void couchbaseCacheExplicitWithTtl() {
+ load(CouchbaseCacheConfiguration.class, "spring.cache.type=couchbase",
+ "spring.cache.cacheNames=foo,bar", "spring.cache.couchbase.expiration=2000");
+ CouchbaseCacheManager cacheManager = validateCacheManager(CouchbaseCacheManager.class);
+ assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar");
+ Cache cache = cacheManager.getCache("foo");
+ assertThat(cache).isInstanceOf(CouchbaseCache.class);
+ assertThat(((CouchbaseCache) cache).getTtl()).isEqualTo(2000);
+ assertThat(((CouchbaseCache) cache).getNativeCache()).isEqualTo(this.context.getBean("bucket"));
+ }
+
@Test
public void redisCacheExplicit() {
load(RedisCacheConfiguration.class, "spring.cache.type=redis");
@@ -733,6 +774,26 @@ public class CacheAutoConfigurationTests {
static class GenericCacheAndCustomizersConfiguration {
}
+ @Configuration
+ @EnableCaching
+ static class CouchbaseCacheConfiguration {
+
+ @Bean
+ public Bucket bucket() {
+ BucketManager bucketManager = mock(BucketManager.class);
+ Bucket bucket = mock(Bucket.class);
+ given(bucket.bucketManager()).willReturn(bucketManager);
+ return bucket;
+ }
+
+ }
+
+ @Configuration
+ @Import({ CouchbaseCacheConfiguration.class, CacheManagerCustomizersConfiguration.class })
+ static class CouchbaseCacheAndCustomizersConfiguration {
+
+ }
+
@Configuration
@EnableCaching
static class RedisCacheConfiguration {
@@ -955,6 +1016,12 @@ public class CacheAutoConfigurationTests {
};
}
+ @Bean
+ public CacheManagerCustomizer couchbaseCacheManagerCustomizer() {
+ return new CacheManagerTestCustomizer() {
+ };
+ }
+
@Bean
public CacheManagerCustomizer redisCacheManagerCustomizer() {
return new CacheManagerTestCustomizer() {
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index aaa30b4990c..424864fa398 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -61,6 +61,7 @@
1.6
2.4.2
2.2.3
+ 2.0.0
1.3.2
10.12.1.1
3.1.2
@@ -525,6 +526,11 @@
java-client
${couchbase-client.version}
+
+ com.couchbase.client
+ couchbase-spring-cache
+ ${couchbase-cache-client.version}
+
com.datastax.cassandra
cassandra-driver-core
diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index f6148a882a8..8803eb0b9cc 100644
--- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -64,6 +64,7 @@ content into your application; rather pick only the properties that you need.
# SPRING CACHE ({sc-spring-boot-autoconfigure}/cache/CacheProperties.{sc-ext}[CacheProperties])
spring.cache.cache-names= # Comma-separated list of cache names to create if supported by the underlying cache manager.
spring.cache.caffeine.spec= # The spec to use to create caches. Check CaffeineSpec for more details on the spec format.
+ spring.cache.couchbase.expiration=0 # Entry expiration in milliseconds. By default the entries never expire.
spring.cache.ehcache.config= # The location of the configuration file to use to initialize EhCache.
spring.cache.guava.spec= # The spec to use to create caches. Check CacheBuilderSpec for more details on the spec format.
spring.cache.hazelcast.config= # The location of the configuration file to use to initialize Hazelcast.
diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index de2bd7a87cf..837fe23ddc4 100644
--- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -3311,6 +3311,7 @@ providers (in this order):
* <>
* <>
* <>
+* <>
* <>
* <>
* <>
@@ -3320,8 +3321,8 @@ It is also possible to _force_ the cache provider to use via the `spring.cache.t
property.
If the `CacheManager` is auto-configured by Spring Boot, you can further tune its
-configuration before it is fully initialized by exposing a bean implementing the
-`CacheManagerCustomizer` interface. The following set the cache names to use.
+configuration before it is fully initialized by exposing a bean implementing the
+`CacheManagerCustomizer` interface. The following sets the cache names to use.
[source,java,indent=0]
----
@@ -3433,6 +3434,56 @@ Caches can be created on startup via the `spring.cache.cache-names` property. If
+[[boot-features-caching-provider-couchbase]]
+==== Couchbase
+If Couchbase is available and <>, a
+`CouchbaseCacheManager` is auto-configured. It is also possible to create additional
+caches on startup using the `spring.cache.cache-names` property. These will operate on
+the `Bucket` that was auto-configured. You can _also_ create additional caches on another
+`Bucket` using the customizer: assume you need two caches on the "main" `Bucket` (`foo`
+and `bar`) and one `biz` cache with a custom time to live of 2sec on the `another`
+`Bucket`. First, you can create the two first caches simply via configuration:
+
+[source,properties,indent=0]
+----
+ spring.cache.cache-names=foo,bar
+----
+
+Then define this extra `@Configuration` to configure the extra `Bucket` and the `biz`
+cache:
+
+
+[source,java,indent=0]
+----
+ @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 cacheManagerCustomizer() {
+ return c -> {
+ c.prepareCache("biz", CacheBuilder.newInstance(anotherBucket())
+ .withExpirationInMillis(2000));
+ };
+ }
+
+ }
+----
+
+This sample configuration reuses the `Cluster` that was created via auto-configuration.
+
+
+
[[boot-features-caching-provider-redis]]
==== Redis
If Redis is available and configured, the `RedisCacheManager` is auto-configured. It is
diff --git a/spring-boot-samples/spring-boot-sample-cache/README.adoc b/spring-boot-samples/spring-boot-sample-cache/README.adoc
index 7ac9474d0fe..d464d72c743 100644
--- a/spring-boot-samples/spring-boot-sample-cache/README.adoc
+++ b/spring-boot-samples/spring-boot-sample-cache/README.adoc
@@ -7,6 +7,7 @@ abstraction is supported by many caching libraries, including:
* `EhCache`
* `Hazelcast`
* `Infinispan`
+* `Couchbase`
* `Redis`
* `Guava`
* Simple provider based on `ConcurrentHashMap`
@@ -78,6 +79,12 @@ can set the `spring.cache.infinispan.config` property to use the provided
+=== Couchbase
+Add the `java-client` and `couchbase-spring-cache` dependencies and make sure that you
+have setup at least a `spring.couchbase.bootstrap-hosts` property.
+
+
+
=== Redis
Add the `spring-boot-starter-data-redis` and make sure it is configured properly (by default,
a redis instance with the default settings is expected on your local box).
diff --git a/spring-boot-samples/spring-boot-sample-cache/pom.xml b/spring-boot-samples/spring-boot-sample-cache/pom.xml
index e54fb393238..631787da88c 100644
--- a/spring-boot-samples/spring-boot-sample-cache/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-cache/pom.xml
@@ -69,6 +69,16 @@
-->
+