Search code examples
javaspring-bootcachinghazelcastspring-cache

Why does Hazelcast not show entry in the Map when added via CachePut/Cacheable


I have a use case where by the @CachePut annotation adds an entry to the cache, and I have to retrieve it manually (via code).

I can see that the total backup count gives me 1 as the number of entries, but all the maps give me the size as 0. So, I am not sure what I am doing wrong.

Here's my code

HazelcastConfig.java

@Configuration
public class HazelcastConfig {

    @Bean
    public Config hazelcastConf() {
        Config c = new Config()
                .setInstanceName("hazelcast-instance")
                .addMapConfig(
                        new MapConfig()
                                .setName("testmap")
                                .setEvictionConfig(
                                        new EvictionConfig()
                                                .setEvictionPolicy(EvictionPolicy.LRU)
                                                .setMaxSizePolicy(MaxSizePolicy.PER_NODE)
                                                .setSize(1000)
                                )
                                .setTimeToLiveSeconds(500000)
                );
        c.getNetworkConfig().getRestApiConfig().setEnabled(true);
        c.getNetworkConfig().getRestApiConfig().enableGroups(RestEndpointGroup.DATA);
        return c;
    }
}

TestServiceImpl.java

@Service
public class TestServiceImpl implements TestService {

    @Autowired
    @Lazy
    private RestTemplate restTemplate;

    @Override
    @CachePut(value = "testmap", key="1")
    public String getId() {

        System.out.println("--------------------------");
        System.out.println("-------INSIDE getId-------");
        String id = null;
        CBObject obj = restTemplate.getForObject("http://localhost:3000/testCB", CBObject.class);
        if (null != obj && null != obj.getId()) {
            id = String.valueOf(obj.getId());
        }
        System.out.println("-------- EXIT getId-------");
        System.out.println("--------------------------");
        return id;
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

TestController.java

@RestController
@RequestMapping("/v1")
public class TestController {


    @Autowired
    private TestService testService;

    @GetMapping("/testCB")
    public ResponseEntity<?> doCB() {
        Map<String, String> resp = new HashMap<>();
        String id = testService.getId();
        if (null != id) {
            resp.put("id", id);
        }
        Config config = new HazelcastConfig().hazelcastConf();
        System.out.println(config.getMapConfig("testmap").getTotalBackupCount()); // 1
        HazelcastInstance hz = Hazelcast.getHazelcastInstanceByName(config.getInstanceName());
        System.out.println(hz.getReplicatedMap("testmap").size()); // 0
        System.out.println(hz.getMap("testmap").size()); // 0
        System.out.println(hz.getMultiMap("testmap").size()); // 0

        return ResponseEntity.status(HttpStatus.ACCEPTED).body(resp);
    }
}


Solution

  • Have you explicitly enabled caching using the @EnableCaching annotation (Ref Doc, Javadoc)?

    Also, see the guidance from Spring Boot in the Ref Doc on Caching if you are using Spring Boot.

    Furthermore, when using Spring Boot, you can either add the command-line switch --debug to your launch command or set the debug property to true in Spring Boot application.properties to get output from the Auto-configuration that has been applied. In particular you will want to see that the CacheAutoConfiguration class has been processed.

    If you are NOT using Spring Boot, then in addition to the @EnableCaching annotation, you will also need to explicitly declare a CacheManager bean, such as:

    @Bean
    HazelcastCacheManager cacheManager(HazelcastInstance hazelcaseInstance) {
      return new HazelcastCacheManager(hazelcastInstance);
    }
    

    This will require the com.hazelcast:hazelcast-spring JAR dependency on your runtime classpath.

    <dependency>
        <groupId>com.hazelcast</groupId>
        <artifactId>hazelcast-spring</artifactId>
        <version>${hazelcast.version}</version>
        <scope>runtime</scope>
    </dependency>
    

    For example.

    NOTE: Do you not confuse the HazelcastCacheManager Spring Cache Abstraction CacheManager implementation, which requires the hazelcast-spring JAR and is required by Spring's Cache Abstraction either with or without Spring Boot, with Hazelcast's standard HazelcastCacheManager. These 2 classes are not the same thing.

    Alternatively, you could also use Hazelcast as a JCache caching provider implementation in either Spring Framework or Spring Boot. The core Spring Framework offers support for using JCache as well. When using Spring Boot, you will need to specify the JCache cache provider type for Hazelcast (i.e. Embedded or Client/Server). I will leave this as an exercise for you to figure out.

    Lastly, I recently built an example for my own testing purposes using Hazelcast as a caching provider in Spring Framework's Cache Abstraction using Spring Boot, if you would like to take a look.

    Hope this helps!

    Cheers!