Improve caching configuration

Rather than creating a `CacheManager` ourselves, we now rely on JCache
to provide a `CacheManager` that we'll augment with the caches that
initializr needs.

If Initializr is embedded in another app and that app uses JCache, then
its cache manager will be transparently upgraded to define the caches
that initializr needs. If not, such caches will have to be created as
part of the custom config.

Also, caching only kicks in if required at the service level.

This commit also switches the cache implementation to EhCache 3.

See gh-389
This commit is contained in:
Stephane Nicoll 2017-03-29 12:55:29 +02:00
parent 8ac7369138
commit 9a83defc4c
4 changed files with 47 additions and 36 deletions

View File

@ -26,6 +26,15 @@
<artifactId>initializr-actuator</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>

View File

@ -23,6 +23,7 @@ import io.spring.initializr.web.project.LegacyStsController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
@ -37,6 +38,7 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
* @author Stephane Nicoll
*/
@SpringBootApplication
@EnableCaching
public class InitializrService {
public static void main(String[] args) {

View File

@ -19,12 +19,13 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<artifactId>spring-boot-starter-mustache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
@ -33,10 +34,6 @@
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
@ -45,10 +42,11 @@
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mustache</artifactId>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>

View File

@ -17,11 +17,11 @@
package io.spring.initializr.web.autoconfigure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.CreatedExpiryPolicy;
import javax.cache.expiry.Duration;
import com.github.benmanes.caffeine.cache.Caffeine;
import io.spring.initializr.generator.ProjectGenerator;
import io.spring.initializr.generator.ProjectRequestPostProcessor;
import io.spring.initializr.generator.ProjectRequestResolver;
@ -38,15 +38,13 @@ import io.spring.initializr.web.support.DefaultInitializrMetadataProvider;
import io.spring.initializr.web.ui.UiController;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@ -65,9 +63,9 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
* @author Stephane Nicoll
*/
@Configuration
@EnableCaching
@EnableConfigurationProperties(InitializrProperties.class)
public class InitializrAutoConfiguration {
@AutoConfigureAfter(CacheAutoConfiguration.class)
public class InitializrAutoConfiguration {
private final List<ProjectRequestPostProcessor> postProcessors;
@ -144,22 +142,26 @@ public class InitializrAutoConfiguration {
return new DefaultDependencyMetadataProvider();
}
@Bean
@ConditionalOnMissingBean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
createConcurrentMapCache(600L, "initializr"),
new ConcurrentMapCache("dependency-metadata"),
new ConcurrentMapCache("project-resources")));
return cacheManager;
}
@Configuration
@ConditionalOnClass(javax.cache.CacheManager.class)
static class CacheConfiguration {
@Bean
public JCacheManagerCustomizer initializrCacheManagerCustomizer() {
return cm -> {
cm.createCache("initializr", config().setExpiryPolicyFactory(
CreatedExpiryPolicy.factoryOf(Duration.TEN_MINUTES)));
cm.createCache("dependency-metadata", config());
cm.createCache("project-resources", config());
};
}
private MutableConfiguration<Object, Object> config() {
return new MutableConfiguration<>()
.setStoreByValue(false)
.setManagementEnabled(true).setStatisticsEnabled(true);
}
private static Cache createConcurrentMapCache(Long timeToLive, String name) {
return new CaffeineCache(name, Caffeine
.newBuilder()
.expireAfterWrite(timeToLive, TimeUnit.SECONDS)
.build());
}
}