Skip to content

Add auto-configuration support for Apache Geode as a caching provider. #6967

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions spring-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-geode</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*
* @author Phillip Webb
* @author Eddú Meléndez
* @author John Blum
*/
final class CacheConfigurations {

Expand All @@ -42,6 +43,7 @@ final class CacheConfigurations {
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
mappings.put(CacheType.GEODE, GeodeCacheConfiguration.class);
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
MAPPINGS = Collections.unmodifiableMap(mappings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* @author Stephane Nicoll
* @author Phillip Webb
* @author Eddú Meléndez
* @author John Blum
* @since 1.3.0
*/
public enum CacheType {
Expand Down Expand Up @@ -66,6 +67,11 @@ public enum CacheType {
*/
CAFFEINE,

/**
* Apache Geode backed caching.
*/
GEODE,

/**
* Simple in-memory caching.
*/
Expand All @@ -74,6 +80,6 @@ public enum CacheType {
/**
* No caching.
*/
NONE;
NONE

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2011-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.autoconfigure.cache;

import java.util.HashSet;

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.client.ClientCache;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.support.GemfireCacheManager;

/**
* GemFire cache configuration.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.support.GemfireCacheManager
* @since 1.5.0
*/
@Configuration
@ConditionalOnBean({ CacheFactoryBean.class, Cache.class,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the condition be on GemfireCache there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. I mean GemfireCache is a class in Spring Data Geode and I cannot obviously use the ConditionalOnBean condition since that is a Spring Boot Condition class.

I somewhat modeled my GeodeCacheConfiguration class after the RedisCacheConfiguration class, and specifically this. RedisTemplate comes from spring-data-redis and it would be weird to put a Condition on the RedisTemplate for caching.

I guess I was maybe a bit paranoid after our discussion about GemFire/Geode being a System of Record (SoR) in certain UCs and overstepping another, perhaps preferred caching solution (e.g. Ehcache) in a Spring Boot user's application. As such I went a little nuts with the Conditional annotations on GeodeCacheConfiguration.

I suppose the following Conditional annotations would be sufficient...

@ConditionalOnClass(GemfireCacheManager.class)
@ConditionalOnMissingBean(CacheManager.class)

I could maybe add a Conditional annotation on GemfireCache in SDG, but I'd rather not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not what I mean. Shouldn't that condition above be @ConditionalOnBean({ CacheFactoryBean.class, GemfireCache.class,... rather than @ConditionalOnBean({ CacheFactoryBean.class, Cache.class,...

Copy link
Contributor Author

@jxblum jxblum Nov 5, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@snicoll - Alright, I see what you are saying now, but, as an FYI, I think you need to be more careful in what you mean. It is not "GemfireCache", it is "GemFireCache"

Unfortunately, there are a bunch of class names in SDG that are inappropriately named (e.g. GemfireTemplate) or confusing (e.g. GemfireCache). Personally, I like the lower case 'f' in the naming, but, it is inconsistent with GemFire/Geode, and has been that way since the project inception, so would very disrupting to users to change the class names now.

My plan is to introduce new configuration models that will allow them to rely less on the SDG API (and naming conventions; and even the GemFire/Geode API for that matter) and more on abstractions I introduce by way of Annotations, that will allow me to clean up the prior mess.

Regarding the recommendations on @ConditionalOnBean bean class references... the SDG FactoryBeans return very specific types (e.g. Cache and ClientCache). In earlier versions of the Spring Framework (possibly as recent as 4.1 and earlier) you could not refer to and inject a GemFire/Geode cache instance generically (i.e. as in GemFireCache); it simply could not resolve the bean type. In fact, I think this problem was specific to the ClientCache interface in particular. Oddly enough, the actual implementing class in GemFire/Geode is GemFireCacheImpl, which implements both Cache and ClientCache.

Then, something changed in latter versions of core Spring Framework where this started working. I suppose I can reconsider this now since Spring Boot 1.5 is based on core Spring Framework 4.3.

ClientCacheFactoryBean.class, ClientCache.class })
@ConditionalOnClass(GemfireCacheManager.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class GeodeCacheConfiguration {

private final CacheProperties cacheProperties;

private final CacheManagerCustomizers cacheManagerCustomizers;

GeodeCacheConfiguration(CacheProperties cacheProperties,
CacheManagerCustomizers cacheManagerCustomizers) {

this.cacheProperties = cacheProperties;
this.cacheManagerCustomizers = cacheManagerCustomizers;
}

@Bean
public GemfireCacheManager cacheManager(GemFireCache gemfireCache) {
GemfireCacheManager cacheManager = new GemfireCacheManager();

cacheManager.setCache(gemfireCache);
cacheManager.setCacheNames(new HashSet<String>(this.cacheProperties.getCacheNames()));

return this.cacheManagerCustomizers.customize(cacheManager);
}
}
Loading