I have a spring application using spring caching based on Guava cache. Due to the high throughput demand and the write-behind functionality, we are now considering migration to Gemfire. I am successful in configuration Gemfire as cache and is able to read and write from the cache. In all the configuration examples, the configuration requires defining of LocalRegionFactory as below:
@Bean
public Region<Long,Person> myPersonRegion(LocalRegionFactoryBean<Long, Person> personRegion) throws Exception {
return personRegion.getObject();
}
@Bean
public LocalRegionFactoryBean<Long, Person> personRegion(GemFireCache cache,AsyncEventQueue gemfireQueue) {
LocalRegionFactoryBean<Long, Person> personRegion = new LocalRegionFactoryBean<>();
personRegion.setCache(cache);
personRegion.setClose(false);
personRegion.setName("person");
personRegion.setAsyncEventQueues(new AsyncEventQueue[]{gemfireQueue});
personRegion.setPersistent(false);
return personRegion;
}
After the beans are defined, we can use @Cacheable(value="person"), @CacheEvict(value="person"). If we directly use a cache name, gemfire throws error that the cache is not defined.
Our experience with Guava ( or Hazelcast, redis etc ) is that , we don't need to explicitly define the caches. It will be automatically created by spring on first occurence.
Is there any way configure gemfire to also behave in the same way ?
The short answer is NO; not exactly.
I am not entirely certain your following statement is completely accurate either...
Our experience with Guava ( or Hazelcast, redis etc ) is that , we don't need to explicitly define the caches.
For Hazelcast, I know this is not true from recent experience (see configuration, and specifically this line). Line 78 is absolutely necessary (in some shape or form, e.g. alternatively XML); without it, Spring's Cache Abstraction will throw an Exception.
Although I have not tested Redis as a caching provider, it does appear Redis can handle dynamic Cache
creation (also this).
It is likely true that Guava, like the ConcurrentMapCacheManager
implementation, does not require pre-existing Caches
be explicitly defined since the ConcurrentMapCacheManager
will dynamically create the Cache
( a ConcurrentHashMap
) at runtime when requested if NOT explicitly "named". However, if the Caches
are explicitly named in advance, then an Exception will be thrown if the Cache
is not already defined (i.e. "named").
I have examples and tests of other caching providers here that illustrate different and rather unique UCs of Spring's Cache Abstraction in practice, identified by the test class or test case names.
However, in all Pivotal GemFire or Apache Geode test examples, you must explicitly create the Region that will serve as the "Cache
" in Spring's caching infrastructure. Although, SDG's GemfireCacheManager
implementation will dynamically create the Spring Cache
object (backed by the underlying Region) that is required by Spring's AOP CacheInterceptor
.
This results in the following, minimal, necessary configuration to enable caching with GemFire/Geode as the provider...
@SpringBootApplication
@EnableCaching
class MyCachingApplication {
public static void main(String[] args) {
SpringApplication.run(MyCachingApplication.class, args);
}
@Bean
GemfireCacheManager cacheManager(GemFireCache gemfireCache) {
GemfireCacheManager cacheManager = new GemfireCacheManager();
cacheManager.setCache(gemfireCache);
return cacheManager;
}
// define all Region beans required by the application including Regions
// used specifically in Spring's Cache Abstraction
}
Now, having said this, I have prototyped dynamic Region creation based on the Spring Cache Abstraction annotations (e.g. @Cacheable
) used throughout the declared application [service] components as can be seen starting with this test. Here is the configuration.
As you can see, there are NO explicit bean definitions for the GemFire Regions that will serve as Caches
in Spring's caching infrastructure. Yet, the application's (test's) Spring @Service
component does make use of caching.
Dynamic Region creation is accomplished by making use of a Spring BeanPostProcessor
(here) and GemFire Functions (using SDG's Function annotation support) to dynamically create the Regions at runtime, during startup. The Function execution is defined here, and the actual Function implementation is defined here.
This example is pretty crude (i.e. does not handle custom Region configuation (e.g. eviction/expiration, persistence, overflow, etc) beyond DataPolicy
) and is currently setup to handle the peer cache topology (i.e. the test application is a peer member/node in the GemFire DS).
However, it is pretty easy to extend this prototype to be used in a client/server topology, take into account all Spring and JSR-107 caching annotations and allow more custom Region configuration.
In time, this maybe something I add to the SDG framework itself.
Hope this helps.
Cheers, John