skip to Main Content

I am trying to create a bean for cacheManager only when a specific cachemanager is not configured.

@Bean
@ConditionalOnProperty(name = "spring.cache.type", matchIfMissing = true)
public CacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager() {

  @Override
  protected Cache createConcurrentMapCache(final String name) {
    return new ConcurrentMapCache(name,
      CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build().asMap(), false);
  }
};

return cacheManager;
}

This bean is created even when I have the property

spring.cache.type=redis

is configured. Did try different combinations with prefix with no luck. This bean is injected regardless of whether the cache type is specified or not in the application.properties.

2

Answers


  1. Your issue is quite straightforward. You need to understand what is actually happening here.

    As you already knows @ConditionalOnProperty creates a bean when the propert specify in your annotation is available in your yml. In your case it is spring.cache.type.

    So if you annotate like this @ConditionalOnProperty(name = "spring.cache.type"), bean will not created when property not is not available. In other words "condition is false because condition is absent".

    When you annotate like this @ConditionalOnProperty(name = "spring.cache.type", matchIfMissing = true), bean will created when the property not available because we explicitly mention that by matchIfMissing = true. In other words "assume condition is true when property is absent". So obviously condition is true when the property is available.

    So to fix your issue what you can do something like this, define a havingValue that will never put as the value for that property. What happens then, bean will not created even when property is available because value of that property does matches your havingValue.

    Something like this,

    @ConditionalOnProperty(name = "spring.cache.type", matchIfMissing = true, havingValue = "none")
    

    Method 2

    You can create custom Condition class. Like follows,

    public class ConditionalOnMisssing implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Environment env = context.getEnvironment();
            return env.getProperty("spring.cache.type") == null;
        }
    }
    

    Then change your CacheManager bean as follows.

    @Bean
    @Conditional(ConditionalOnMisssing.class)
    public CacheManager cacheManager() {}
    
    Login or Signup to reply.
  2. The issue seems to be that the default value of having attribute does not work as you expect it to. Reading the reference documentation you will find the following for having:

    The string representation of the expected value for the properties. If not specified, the property must not be equal to false.

    This means, that in your case (because you are not specifying the value), the condition will always match unless you have spring.cache.type=false. This is also shown in the reference documentation in the following table (the property value "foo" will actually match the condition if havingValue="" which is actually the default if you do not specify it):
    enter image description here

    Having said all that I would say that your best option would be to create your own Condition just like @ray suggested.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search