Skip to content

Commit

Permalink
Add Caffeine cache support
Browse files Browse the repository at this point in the history
  • Loading branch information
eddumelendez authored and snicoll committed Feb 29, 2016
1 parent 41f0a5c commit 98cc683
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 4 deletions.
5 changes: 5 additions & 0 deletions spring-boot-actuator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@
<artifactId>hal-browser</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
Expand All @@ -18,6 +18,7 @@

import javax.cache.Caching;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.hazelcast.core.IMap;
import com.hazelcast.spring.cache.HazelcastCache;
import net.sf.ehcache.Ehcache;
Expand All @@ -26,6 +27,7 @@

import org.springframework.boot.actuate.cache.CacheStatistics;
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
import org.springframework.boot.actuate.cache.CaffeineCacheStatisticsProvider;
import org.springframework.boot.actuate.cache.ConcurrentMapCacheStatisticsProvider;
import org.springframework.boot.actuate.cache.DefaultCacheStatistics;
import org.springframework.boot.actuate.cache.EhCacheStatisticsProvider;
Expand All @@ -40,6 +42,7 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.ehcache.EhCacheCache;
import org.springframework.cache.guava.GuavaCache;
Expand All @@ -54,6 +57,7 @@
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Eddú Meléndez
* @since 1.3.0
*/
@Configuration
Expand All @@ -72,6 +76,17 @@ public JCacheCacheStatisticsProvider jCacheCacheStatisticsProvider() {

}

@Configuration
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
static class CaffeineCacheStatisticsProviderConfiguration {

@Bean
public CaffeineCacheStatisticsProvider caffeineCacheStatisticsProvider() {
return new CaffeineCacheStatisticsProvider();
}

}

@Configuration
@ConditionalOnClass({ EhCacheCache.class, Ehcache.class, StatisticsGateway.class })
static class EhCacheCacheStatisticsProviderConfiguration {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.actuate.cache;

import com.github.benmanes.caffeine.cache.stats.CacheStats;

import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;

/**
* {@link CacheStatisticsProvider} implementation for Caffeine.
*
* @author Eddú Meléndez
* @since 1.4.0
*/
public class CaffeineCacheStatisticsProvider
implements CacheStatisticsProvider<CaffeineCache> {

@Override
public CacheStatistics getCacheStatistics(CacheManager cacheManager,
CaffeineCache cache) {
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
statistics.setSize(cache.getNativeCache().estimatedSize());
CacheStats caffeineStatistics = cache.getNativeCache().stats();
if (caffeineStatistics.requestCount() > 0) {
statistics.setHitRatio(caffeineStatistics.hitRate());
statistics.setMissRatio(caffeineStatistics.missRate());
}
return statistics;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.cache.Caching;
import javax.cache.configuration.MutableConfiguration;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.cache.CacheBuilder;
import com.hazelcast.cache.HazelcastCachingProvider;
import com.hazelcast.config.Config;
Expand All @@ -40,6 +41,7 @@
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerUtils;
Expand All @@ -60,6 +62,7 @@
* Tests for {@link CacheStatisticsAutoConfiguration}.
*
* @author Stephane Nicoll
* @author Eddú Meléndez
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CacheStatisticsAutoConfigurationTests {
Expand Down Expand Up @@ -145,6 +148,14 @@ public void noOpCacheStatistics() {
assertCoreStatistics(updatedCacheStatistics, null, null, null);
}

@Test
public void caffeineCacheStatistics() {
load(CaffeineCacheConfig.class);
CacheStatisticsProvider provider = this.context
.getBean("caffeineCacheStatisticsProvider", CacheStatisticsProvider.class);
doTestCoreStatistics(provider, true);
}

private void doTestCoreStatistics(CacheStatisticsProvider provider,
boolean supportSize) {
Cache books = getCache("books");
Expand Down Expand Up @@ -313,4 +324,17 @@ public NoOpCacheManager cacheManager() {

}

@Configuration
static class CaffeineCacheConfig {

@Bean
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder().recordStats());
cacheManager.setCacheNames(Arrays.asList("books", "speaker"));
return cacheManager;
}

}

}
5 changes: 5 additions & 0 deletions spring-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,11 @@
<artifactId>thymeleaf-layout-dialect</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.mxab.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-data-attribute</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
Expand All @@ -26,6 +26,7 @@
* Mappings between {@link CacheType} and {@code @Configuration}.
*
* @author Phillip Webb
* @author Eddú Meléndez
*/
final class CacheConfigurations {

Expand All @@ -42,6 +43,7 @@ private CacheConfigurations() {
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
mappings.put(CacheType.GUAVA, GuavaCacheConfiguration.class);
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
Expand Down Expand Up @@ -44,6 +44,8 @@ public class CacheProperties {
*/
private List<String> cacheNames = new ArrayList<String>();

private final Caffeine caffeine = new Caffeine();

private final EhCache ehcache = new EhCache();

private final Hazelcast hazelcast = new Hazelcast();
Expand All @@ -70,6 +72,10 @@ public void setCacheNames(List<String> cacheNames) {
this.cacheNames = cacheNames;
}

public Caffeine getCaffeine() {
return this.caffeine;
}

public EhCache getEhcache() {
return this.ehcache;
}
Expand Down Expand Up @@ -106,6 +112,27 @@ public Resource resolveConfigLocation(Resource config) {
return null;
}

/**
* Caffeine specific cache properties.
*/
public static class Caffeine {

/**
* The spec to use to create caches. Check CaffeineSpec for more details on
* the spec format.
*/
private String spec;

public String getSpec() {
return this.spec;
}

public void setSpec(String spec) {
this.spec = spec;
}

}

/**
* EhCache specific cache properties.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* 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.
Expand Down Expand Up @@ -56,6 +56,11 @@ public enum CacheType {
*/
REDIS,

/**
* Caffeine backed caching.
*/
CAFFEINE,

/**
* Guava backed caching.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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 com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.CaffeineSpec;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

/**
* Caffeine cache configuration.
*
* @author Eddú Meléndez
* @since 1.4.0
*/
@Configuration
@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })
@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)
@Conditional({ CacheCondition.class })
class CaffeineCacheConfiguration {

@Autowired
private CacheProperties cacheProperties;

@Autowired(required = false)
private Caffeine<Object, Object> caffeine;

@Autowired(required = false)
private CaffeineSpec caffeineSpec;

@Autowired(required = false)
private CacheLoader<Object, Object> cacheLoader;

@Bean
@ConditionalOnMissingBean
public CaffeineCacheManager caffeineCacheManager() {
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
setCacheBuilder(caffeineCacheManager);
if (this.cacheLoader != null) {
caffeineCacheManager.setCacheLoader(this.cacheLoader);
}
caffeineCacheManager.setCacheNames(this.cacheProperties.getCacheNames());
return caffeineCacheManager;
}

private void setCacheBuilder(CaffeineCacheManager caffeineCacheManager) {
String specification = this.cacheProperties.getCaffeine().getSpec();
if (StringUtils.hasText(specification)) {
caffeineCacheManager.setCaffeine(Caffeine.from(specification));
}
else if (this.caffeineSpec != null) {
caffeineCacheManager.setCaffeine(Caffeine.from(this.caffeineSpec));
}
else if (this.caffeine != null) {
caffeineCacheManager.setCaffeine(this.caffeine);
}
}

}
Loading

0 comments on commit 98cc683

Please sign in to comment.