javaspring-bootqualifiers

Spring boot: Bean and dynamic Qualifiers


Considering the following spring-boot snippet:

// AppConfig.java

@Configuration
public class AppConfig {
    @Bean
    public PersonService users(ICache cache) {
        return new PersonServiceImpl(cache);
    }

  @Bean
  public ICache redis() {
        return new RedisCache();
    }

  @Bean
  public ICache memory() {
        return new MemoryCache();
    }
}
// PersonController.java

@RestController
public class PersonController { 
    @Autowired
    private PersonService users; 
      
    @Getmapping("/api/v1/person") 
    public List<PersonV1> getAllV1(){ 
      return users.getAllV1(); 
    } 
    
    @Getmapping("/api/v2/person") 
    public List<PersonV2> getAllV2(){ 
      return users.getAllV2(); 
    } 
}

I would like to configure spring to automatically wire endpoints from both v1 and v2 to the PersonService. However, for the v1 endpoint, I want to retrieve data from the PersonService using Memory cache as its backend, while for the v2 endpoint, I have to fetch data from Redis cache backend. If spring boot does not support this directly, what would be the best practice to achieve this? Can I use @Conditional for this purpose?


Solution

  • Considering you want to have both versions running you can make use of @Qualifier. This annotation can be used when there are multiple beans of the same type and you want to wire only one of them with a property.

    @Configuration
    public class AppConfig {
    
        @Bean
        @Qualifier("memoryCachePersonService")
        public PersonService usersMemoryCache() {
            return new PersonServiceImpl(memoryCache());
        }
    
        @Bean
        @Qualifier("redisCachePersonService")
        public PersonService usersRedisCache() {
             return new PersonServiceImpl(redisCache());
         }
    
        @Bean
        public ICache redisCache() {
             return new RedisCache();
         }
    
        @Bean
        public ICache memoryCache() {
            return new MemoryCache();
        }
    }
    

    And your Controller:

    @RestController
    public class PersonController {
    
        @Autowired
        @Qualifier("memoryCachePersonService")
        private PersonService usersMemory;
    
        @Autowired
        @Qualifier("redisCachePersonService")
        private PersonService usersRedis;
    
        @GetMapping("/api/v1/person") 
        public List<PersonV1> getAllV1(){ 
            return usersMemory.getAllV1(); 
        } 
        
        @GetMapping("/api/v2/person") 
        public List<PersonV2> getAllV2(){ 
            return usersRedis.getAllV2(); 
        } 
    }
    

    You can find more information about how @Qualifier works on Spring boot documentation

    You can even make use of @Primaryif that fits to you