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> <artifactId>initializr-actuator</artifactId>
</dependency> </dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId> <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.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport; import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
@ -37,6 +38,7 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@SpringBootApplication @SpringBootApplication
@EnableCaching
public class InitializrService { public class InitializrService {
public static void main(String[] args) { public static void main(String[] args) {

View File

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

View File

@ -17,11 +17,11 @@
package io.spring.initializr.web.autoconfigure; package io.spring.initializr.web.autoconfigure;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; 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.ProjectGenerator;
import io.spring.initializr.generator.ProjectRequestPostProcessor; import io.spring.initializr.generator.ProjectRequestPostProcessor;
import io.spring.initializr.generator.ProjectRequestResolver; 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 io.spring.initializr.web.ui.UiController;
import org.springframework.beans.factory.ObjectProvider; 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.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.EnableConfigurationProperties; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
@ -65,9 +63,9 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@Configuration @Configuration
@EnableCaching
@EnableConfigurationProperties(InitializrProperties.class) @EnableConfigurationProperties(InitializrProperties.class)
public class InitializrAutoConfiguration { @AutoConfigureAfter(CacheAutoConfiguration.class)
public class InitializrAutoConfiguration {
private final List<ProjectRequestPostProcessor> postProcessors; private final List<ProjectRequestPostProcessor> postProcessors;
@ -144,22 +142,26 @@ public class InitializrAutoConfiguration {
return new DefaultDependencyMetadataProvider(); return new DefaultDependencyMetadataProvider();
} }
@Bean @Configuration
@ConditionalOnMissingBean @ConditionalOnClass(javax.cache.CacheManager.class)
public CacheManager cacheManager() { static class CacheConfiguration {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList( @Bean
createConcurrentMapCache(600L, "initializr"), public JCacheManagerCustomizer initializrCacheManagerCustomizer() {
new ConcurrentMapCache("dependency-metadata"), return cm -> {
new ConcurrentMapCache("project-resources"))); cm.createCache("initializr", config().setExpiryPolicyFactory(
return cacheManager; 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());
} }
} }