0

I'm creating multiple Caffeine caches like:

@Bean
public Cache<String, Customer> customerCache() {
    return Caffeine.newBuilder()
            .maximumSize(10_000)
            // other config settings
            .build(..);
}

Now I would like to use something like a @ConfigurationProperties(prefix = "cache.customer") to set the builder config options.

Where a application property cache.customer.maximum-size: 1000 exists.

Is there something smart I can do to map the @ConfigurationProperties to the Caffeine builder?

Marcel Overdijk
  • 11,041
  • 17
  • 71
  • 110

3 Answers3

2

For future readers here is code I used to use Spring Boot's @ConfigurationProperties to configure a Caffeine Cache:

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

/**
 * Base class for configuration of a Caffeine {@link Cache}
 */
public class CaffeineCacheProperties {

    private Integer maximumSize;

    // TODO: Add additional properties + getters and setters.

    public Integer getMaximumSize() {
        return maximumSize;
    }

    public void setMaximumSize(final Integer maximumSize) {
        this.maximumSize = maximumSize;
    }

    public Caffeine initializeCacheBuilder() {
        Caffeine cacheBuilder = Caffeine.newBuilder();
        if (maximumSize != null) {
            cacheBuilder.maximumSize(maximumSize);
        }
        // TODO: Configure additional properties.
        return cacheBuilder;
    }
}

.

import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * The cache {@link Configuration} class.
 */
@Configuration
public class CacheConfig {

    @Bean
    @ConfigurationProperties("cache.customer")
    public CaffeineCacheProperties customerCacheProperties() {
        return new CacheProperties();
    }

    @Bean
    public Cache<String, Customer> customerCache() {
        return customerCacheProperties().initializeCacheBuilder().build();
    }

    // TODO: Add other caches.
}

And then add a application property like:

cache.customer.maximum-size: 1000
Marcel Overdijk
  • 11,041
  • 17
  • 71
  • 110
0

You can do something similar to what the boot team has done with DataSourceProperties:

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java

You bind your properties into a property class and then use a method on that properties class to create your builder.

Here is a different example where we are binding both the properties and a data source to the same root:

    @Bean
    @ConfigurationProperties("datasource.task")
    public DataSourceProperties taskDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = {"taskDataSource"}, destroyMethod="")
    @ConfigurationProperties("datasource.task")
    @ConditionalOnMissingBean(name="taskDataSource")
    public DataSource taskDataSource() {
        return taskDataSourceProperties().initializeDataSourceBuilder().build();
    }
Tyler Van Gorder
  • 453
  • 6
  • 14
  • Thx a lot this was exactly I was looking for. I tried this before but forgot to add the @Beat annotation to the properties bean (which is than not proxied). – Marcel Overdijk Aug 24 '18 at 20:04
-1

You can use @ConfigurationProperties(prefix = "cache.customer") on top of your CacheConfig class (A configurations class) where you can easily bind the application properties to your Cache class by using @EnableConfigurationProperties(CacheConfig.class). So now you can auto wire the CacheConfig class to your Cache class and save it as a private attribute in your cache class. And then you can use that configurations through builder like

@Bean
public Cache<String, Customer> customerCache() {
    return Caffeine.newBuilder()
            .maximumSize(cacheConfig.getMaximumSize())
            // other config settings
            .build(..);
}
Damith
  • 740
  • 4
  • 12
  • The thing is I'm creating multiple caches, so can't use the @ConfigurationProperties(prefix = "cache.customer") on top of my CacheConfig class. Besides that I would like a more advanced way then setting each property manually. Like Spring Boot's DataSourceBuilder. Thx for your suggestion anyway. – Marcel Overdijk Aug 23 '18 at 11:13
  • Interesting requirement. But my concern is @ConfigurationProperties wont help unless you use different prefixes right? It means you may have different Config classes for each configuration. I am not sure whether spring supports other than that scenario with configuration loading ( application properties) – Damith Aug 23 '18 at 11:28
  • I think how it works now is that @ConfigurationProperties simply changes the bean returned by the method. In my case that is to late. I was looking at the source of the DataSourceBuilder but the binding didn't worked either. – Marcel Overdijk Aug 23 '18 at 11:31
  • I think if your configurations are pre-defined ( can have all them in application.properties file) which will not changed in run-time, having different prefixes should work. If your configuration is defined runtime, ( like maximumSize will be changed based on a logic) Then you can change those configurations in your CacheConfig file and Autowire that to your builder. Problem is spring is executing the constructor before it autowire private variables. so If you autowire your CacheConfig class to your builder constructor, your application should work. Correct me if I am missing anything – Damith Aug 23 '18 at 11:50