1

It looks like the default Spring boot auto configuration will create two hazelcast instances when using JCache and caching is enabled (@EnableCaching)

Full example at: https://github.com/dirkvanrensburg/hazelcast-springboot-jcache

TLDR; Is there a way to get Spring boot's autoconfiguration to only create one Hazelcast instance when enabling caching through JCache?

I created a demo Spring boot project by adding the following dependencies:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.cache</groupId>
        <artifactId>cache-api</artifactId>
    </dependency>

    <dependency>
        <groupId>com.hazelcast</groupId>
        <artifactId>hazelcast</artifactId>
    </dependency>

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

and adding @EnableCaching to the Application class, Spring will auto configure Hazelcast but start two hazelcast instances, which joins in a cluster as evidenced in the logs:

Members [2] {
    Member [192.168.1.157]:5701 - 3eabbe90-6815-49ff-8d93-9e4b12e67810
    Member [192.168.1.157]:5702 - e9c93366-2408-4726-965a-b21dcf897113 this
}

The caching works but I don't want two instances of Hazelcast.

Hack

I managed to make it work by providing my own cache manager:

@Bean
public CacheManager springHzProvider(HazelcastInstance instance) {
    return SpringHazelcastCachingProvider.getCacheManager(instance, null, new Properties());
}

and removing the hazelcast and hazelcast-spring dependencies and adding hazelcast-all:

    <dependency>
        <groupId>com.hazelcast</groupId>
        <artifactId>hazelcast-all</artifactId>
        <version>${hazelcast.version}</version>
    </dependency>

But the question remains whether there is better 'proper' way of achieving this? Ideally without defining a custom cache manager and adding hazelcast-all

dvanrensburg
  • 1,351
  • 1
  • 14
  • 21
  • See https://github.com/hazelcast/hazelcast-code-samples/tree/master/hazelcast-integration/springboot-caching-jcache. You can add the `@EnableAutoConfiguration` annotation to exclude Spring Boot's `HazelcastAutoConfigurtation` class and remove your `springHzProvider` method. It's not an ideal solution but a bit cleaner. – Neil Stevenson Feb 10 '17 at 08:23
  • Thanks, that works and is actually much cleaner. I don't have to add `HazelcastClientProxy` to the classpath. Do you understand what is going on here? Is it perhaps a bug in `CacheAutoConfiguration` ? If you want to add your comment as an answer then I'll accept it since it addresses both of my concerns (custom cachemanager, adding hazelcast-all) – dvanrensburg Feb 11 '17 at 23:33
  • I'll raise it as an issue with Spring Boot first, and add the link – Neil Stevenson Feb 13 '17 at 08:46
  • 1
    Just a follow-up that the issue has now been fixed and will be available as of Spring Boot `1.5.3.RELEASE` – Stephane Nicoll Mar 10 '17 at 15:40

2 Answers2

3

@dvanrensburg As per the comments, as a temporary solution exclude the HazelcastAutoConfiguration class from auto-configuration. I have logged an issue with Spring Boot https://github.com/spring-projects/spring-boot/issues/8275 as I think that's the root cause, the second instance shouldn't be created if @EnableCaching has triggered the creation of the first.

Neil Stevenson
  • 3,060
  • 9
  • 11
1

I used Neil's solution above but ran into the situation where I cannot autowire the Hazelcast instance created by the JCache configuration. It looks like the instance is created outside of Spring and registered with the application context.

Giving the instance a name in the config

<instance-name>test</instance-name>

and then adding an explicit hook to bring the instance into the context

@Bean
public HazelcastInstance getInstance() {
    return Hazelcast.getHazelcastInstanceByName("test");
}

works well. The HazelcastAutoconfiguration won't run since it has a conditional on the instance not existing yet.

My only concern is that this rely heavily on the fact that for version 1.5.1 of Spring Boot the JCache configuration creates this instance before the HazelcastAutoconfiguration kicks in.

UPDATE I found a better solution with the help from the @snicoll of the excellent Spring Boot community.

Just explicitly tell Spring Boot which hazelcast config to use and name the Hazelcast instance. Put the following in application.properties spring.hazelcast.config=hazelcast.xml

For an example see: https://github.com/dirkvanrensburg/hazelcast-springboot-jcache/tree/fixed

dvanrensburg
  • 1,351
  • 1
  • 14
  • 21
  • Even when I use explicit `spring.hazelcast.config` there're still 2 hazelcast instances running, but now they're forming single cluster :'D. – Michał Stochmal Apr 26 '23 at 12:22