spring-cloud / spring-cloud-gateway

An API Gateway built on Spring Framework and Spring Boot providing routing and more.
http://cloud.spring.io
Apache License 2.0
4.52k stars 3.32k forks source link

Failure startup due to multiple CacheManager beans when using Caffeine #2853

Closed kewshah4 closed 7 months ago

kewshah4 commented 1 year ago

Describe the bug

I am using spring-boot 3.0.2 and spring-cloud 2022.0.1. I am injecting the CacheManager as a @Bean method parameter, for example

@Bean("test")
public String myCache(CacheManager caffeineCacheManager) {
   return caffeineCacheManager.toString();
}

this results in a conflict with the CacheManager bean now being created in LocalResponseCacheAutoConfiguration.

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-01-30T13:18:53.409+05:30 ERROR 46333 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method myCache in com.example.cachebug.configuration.MyCache required a single bean, but 2 were found:
    - cacheManager: defined by method 'cacheManager' in class path resource [org/springframework/boot/autoconfigure/cache/CaffeineCacheConfiguration.class]
    - gatewayCacheManager: defined by method 'gatewayCacheManager' in class path resource [org/springframework/cloud/gateway/config/LocalResponseCacheAutoConfiguration.class]

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

I tried adding @Qualifier("cacheManager") to the @Bean method parameter, but it didn't work.

Sample https://github.com/kewshah4/cache-bug

Possibly related to

2841

rougou commented 1 year ago

The documentation says:

If your project creates custom CacheManager beans, it will either need to be marked with @Primary or injected using @Qualifier.

The error you posted seems to be caused by your own code. Your need to put @Qualifier where you inject the bean (MyCache in your case). That said, I'm getting a similar error in Spring's code, so adding @Qualifier doesn't help me. I have 2 custom CacheManager beans, and I have to add @Primary to the first one to avoid this error:

java.lang.IllegalStateException: No CacheResolver specified, and no unique bean of type CacheManager found. Mark one as primary or declare a specific CacheManager to use.
    at org.springframework.cache.interceptor.CacheAspectSupport.afterSingletonsInstantiated(CacheAspectSupport.java:223)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:972)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:917)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)

It should also be noted that the Spring Cloud Gateway (3.0.1) included in spring-cloud 2022.0.1 has a bug where LocalResponseCacheAutoConfiguration is enabled by default, otherwise the gatewayCacheManager bean wouldn't exist to begin with. You can override the gateway version for now:

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-gateway-dependencies</artifactId>
        <version>4.0.3</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2022.0.1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
licenziato commented 1 year ago

I managed to make it work, doing: