0

I have created to Hazelcast map config in one instance. I have a bean method inside config which sends separate maps in 2 different methods. Class CacheService has a field which will be injected by any one of those methods.

I am trying to use Qualifier annotation to get instance of CacheService, but I need one CacheService instance to hold a variable from first type bean method return value and second instance to have the second bean return value. PS: I use lombok for auto constructor and injection How can I achieve this?

I tried using Qualifiers in the @bean annotation method and create two seperate class for CacheService with qualifiers inside for fields, which didn't work.

Config Class

@Bean
public IMap<String, Object> mainCache(HazelcastInstance hazelcastInstance) {

        return hazelcastInstance.getMap(mainCache);
    }
@Bean
public IMap<String, Object> secCache(HazelcastInstance hazelcastInstance) {
        return hazelcastInstance.getMap(SecondaryCache);
    }

Class that uses bean method's value

@Service
@RequiredArgsConstructor
public class CacheService {

//Value that needs to be dynamic based on the qualifier
    private final IMap<String, Object> cache;

    public void put(String key, Object value) {
        cache.put(key, value);
    }

    public Object get(String key) {
        return cache.get(key);
    }

    public <T> T get(String key, Class<T> type) {
        return type.cast(cache.get(key));
    }
}

Class with a problem

@RequiredArgsConstructor
@EnableAspectJAutoProxy
public class CacheCalculationInterceptor {
        //I need this instance with CacheService's variable IMap as returned by mainCache method of config class
    private final CacheService mainCacheService;
        //I need this instance with CacheService's variable IMap as returned by secCache method of config class
    private final CacheService secCacheService;

As I mentioned in comment I need 2 instances of CacheService class that has fields with different values from 2 different bean method. But I am getting "Parameter 0 of constructor in CacheService required a single bean, but 2 were found:"

Codex
  • 1,153
  • 1
  • 20
  • 31
  • put names on beans @Bean("something1") @Bean("something2") and @Qualifier("somethind1") @Qualifier("somethind2") where you need to call them. that is it. – Jonathan JOhx Aug 01 '19 at 15:36

3 Answers3

1

@Service defines a singleton bean, i.e. there is only one instance of it!!!

To have multiple instances with different injected values, you should create the instances with a @Configuration class, same as you're doing for the cache itself.

Alternatively, you could also use subclasses, e.g.

Config Class

@Bean
@Qualifier("main")
public IMap<String, Object> mainCache(HazelcastInstance hazelcastInstance) {
    return hazelcastInstance.getMap(mainCache);
}
@Bean
@Qualifier("secondary")
public IMap<String, Object> secCache(HazelcastInstance hazelcastInstance) {
    return hazelcastInstance.getMap(SecondaryCache);
}

Service Classes

public abstract class CacheService {
    private final IMap<String, Object> cache;
    protected CacheService(IMap<String, Object> cache) {
        this.cache = cache;
    }
}
@Service
@Qualifier("main")
public class MainCacheService extends CacheService {
    public MainCacheService(@Qualifier("main") IMap<String, Object> cache) {
        super(cache);
    }
}
@Service
@Qualifier("secondary")
public class SecondaryCacheService extends CacheService {
    public SecondaryCacheService(@Qualifier("secondary") IMap<String, Object> cache) {
        super(cache);
    }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thank you for the comment @Andreas. I understand your approach, but its still throwing same error. Let me troubleshoot and look at other answers as well. – Codex Aug 01 '19 at 20:34
1

The Lombok constructor generation will not allow you to specify the qualifiers for the two CacheServices instances.

To achieve that the CacheServices should be declared as @Bean with the expected qualifiers for each one in parameters.

In CacheService declare a constructor that accepts the cache parameter :

public class CacheService {
     private IMap<String, Object> cache;
     public CacheService(IMap<String, Object> cache){
         this.cache = cache;
     }
}

And declare two beans for this class :

@Configuration
public class CacheConfiguration {
        //I need this instance with CacheService's variable IMap as returned by mainCache method of config class
      public CacheService mainCacheService(@Qualifier("mainCache") IMap<String, Object> cache){
         return new CacheService(cache);
      }

      //I need this instance with CacheService's variable IMap as returned by     
     public CacheService secCacheService(@Qualifier("secCache") IMap<String, Object> cache){
         return new CacheService(cache);
      }
}

Follow the same approach for CacheCalculationInterceptor that requires these beans :

@EnableAspectJAutoProxy
public class CacheCalculationInterceptor {
        //I need this instance with CacheService's variable IMap as returned by mainCache method of config class
    private final CacheService mainCacheService;
        //I need this instance with CacheService's variable IMap as returned by secCache method of config class
    private final CacheService secCacheService;

    public CacheCalculationInterceptor(@Qualifier("mainCacheService") CacheService mainCacheService, @Qualifier("secCacheService") CacheService secCacheService){
      this.mainCacheService = mainCacheService;
      this.secCacheService = secCacheService;
   }

 }
davidxxx
  • 125,838
  • 23
  • 214
  • 215
1

You cannot achieve this by using @Service annotation, but there is way to achieve this by using @Bean annotation with constructor injection

CacheService

public class CacheService {

//Value that needs to be dynamic based on the qualifier
private final IMap<String, Object> cache;

@Autowire
public CacheService(IMap<String, Object> cache)  {
     this.cache=cache;
   }

public void put(String key, Object value) {
    cache.put(key, value);
   }

public Object get(String key) {
    return cache.get(key);
    }

public <T> T get(String key, Class<T> type) {
    return type.cast(cache.get(key));
   }
}

Config Class In the define two beans of CacheService with respective IMap

@Bean
public IMap<String, Object> mainCache(HazelcastInstance hazelcastInstance) {

    return hazelcastInstance.getMap(mainCache);
}
 @Bean
 public IMap<String, Object> secCache(HazelcastInstance hazelcastInstance) {
    return hazelcastInstance.getMap(SecondaryCache);
}

 @Bean
 public CacheService getMainCacheService(@Qualifier("mainCache") IMap<String, Object> mainCache) {
   return new CacheService(mainCache);
  }

  @Bean
 public CacheService getSecCacheService(@Qualifier("secCache") IMap<String, Object> secCache) {
   return new CacheService(secCache);
  }
Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98