I have a project using Spring Boot 2.4.1 and Hazelcast 4.1.1. I am trying to use Spring Boot autoconfiguration to setup a distributed map with a read through using a JpaRepository to populate the map. I've added application.yaml and hazelcast.yaml and provided an implementation of com.hazelcast.map.MapLoader
and com.hazelcast.map.MapLoaderLifecycleSupport
annotated with @SpringAware
. A hazelcast instance is started ok, but the MapLoader is never invoked. The hazelcast documentation just provides Spring XML config examples
com.hazelcast.config.MapConfig
and com.hazelcast.config.Config
beans?@SpringAware
with the MapLoader?Any guidance that you can provide would be much appreciated. Below is what I've attempted so far:
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-all</artifactId>
<version>4.1.1</version>
</dependency>
application.yaml:
# datasource and JPA config omitted
spring:
hazelcast:
config: classpath:hazelcast.yaml
hazelcast.yaml
hazelcast:
cluster-name: hazelcast-cluster
map:
myResourceMap:
map-loader:
enabled: true
initial-mode: EAGER
class-name: com.dev.hz.MyResourceMaploader
MapLoader implementation:
@SpringAware
public class MyResourceMapLoader implements MapLoader<Long, MyResource>, MapLoaderLifecycleSupport {
private final MyResourceRepository repo;
public MyResourceMapLoader(MyResourceRepository repo) {
this.repo = repo;
}
@Override
public MyResource load(Long key) {
return this.repo.findById(key).orElse(null);
}
@Override
public Map<Long, MyResource> loadAll(Collection<Long> keys) {
Map<Long, MyResource> myResourceMap = new HashMap<>();
for (Long key : keys) {
MyResource myResource = this.load(key);
if (myResource != null) {
myResourceMap.put(key, myResource);
}
}
return myResourceMap;
}
@Override
public Iterable<Long> loadAllKeys() {
return this.repo.findAllIds();
}
@Override
public void init(HazelcastInstance hazelcastInstance, Properties properties, String mapName) {
}
@Override
public void destroy() {
}
}
One way is by having a @Component
class that implements MapStoreFactory
. The factory needs to implement:
MapLoader newMapStore(String mapName, Properties properties)
and can use the map name to find the relevant bean.
Then in your @Configuration
you can inject the factory, and use it to set the factory implementation on the map's map store configuration object.
This may also be a solution, though I've not tried it.