Skip to content

Commit

Permalink
Future cache support started
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-krecan committed May 5, 2015
1 parent 8853107 commit 48329ff
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

package org.springframework.cache.config;

import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.scheduling.annotation.AsyncResult;

/**
* @author Costin Leau
Expand All @@ -38,6 +40,11 @@ public Object cache(Object arg1) {
return counter.getAndIncrement();
}

@Override
public Future<Object> cacheFuture(Object arg1) {
return new AsyncResult<>(counter.getAndIncrement());
}

@Override
public Object conditional(int field) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.cache.config;

import java.util.concurrent.Future;

/**
* Basic service interface.
*
Expand All @@ -26,6 +28,8 @@ public interface CacheableService<T> {

T cache(Object arg1);

Future<T> cacheFuture(Object arg1);

void invalidate(Object arg1);

void evictEarly(Object arg1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.scheduling.annotation.AsyncResult;

import java.util.concurrent.Future;

/**
* Simple cacheable service
Expand All @@ -40,6 +43,11 @@ public Long cache(Object arg1) {
return counter.getAndIncrement();
}

@Override
public Future<Long> cacheFuture(Object arg1) {
return new AsyncResult<>(counter.getAndIncrement());
}

@Override
@CacheEvict("testCache")
public void invalidate(Object arg1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.cache.interceptor;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -41,13 +42,16 @@
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.expression.EvaluationContext;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;

/**
* Base class for caching aspects, such as the {@link CacheInterceptor}
Expand Down Expand Up @@ -335,6 +339,10 @@ private Object execute(CacheOperationInvoker invoker, CacheOperationContexts con
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

if (cacheHit != null && cacheHit.get() instanceof ListenableFutureCacheValueWrapper) {
cacheHit = new SimpleValueWrapper(new AsyncResult<>(((ListenableFutureCacheValueWrapper) cacheHit.get()).getValue()));
}

// Collect puts from any @Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
Expand All @@ -353,6 +361,24 @@ private Object execute(CacheOperationInvoker invoker, CacheOperationContexts con
result = new SimpleValueWrapper(invokeOperation(invoker));
}

if (result.get() instanceof ListenableFuture) {
((ListenableFuture) result.get()).addCallback(new ListenableFutureCallback() {
@Override
public void onSuccess(Object result) {
postProcessCache(contexts, cachePutRequests, new SimpleValueWrapper(new ListenableFutureCacheValueWrapper(result)));
}
@Override
public void onFailure(Throwable ex) {

}
});
} else {
postProcessCache(contexts, cachePutRequests, result);
}
return result.get();
}

private void postProcessCache(CacheOperationContexts contexts, List<CachePutRequest> cachePutRequests, Cache.ValueWrapper result) {
// Collect any explicit @CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);

Expand All @@ -363,8 +389,6 @@ private Object execute(CacheOperationInvoker invoker, CacheOperationContexts con

// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());

return result.get();
}

private boolean hasCachePut(CacheOperationContexts contexts) {
Expand Down Expand Up @@ -710,4 +734,20 @@ public int hashCode() {
return (this.cacheOperation.hashCode() * 31 + this.methodCacheKey.hashCode());
}
}


/**
* We have to see if the value retrieved from cache should be converted to ListenableFuture.
*/
private static final class ListenableFutureCacheValueWrapper implements Serializable {
private final Object value;

private ListenableFutureCacheValueWrapper(Object value) {
this.value = value;
}

public Object getValue() {
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ public void testCacheable(CacheableService<?> service) throws Exception {
assertSame(r1, r3);
}

public void testCacheableFuture(CacheableService<?> service) throws Exception {
Object o1 = new Object();

Object r1 = service.cacheFuture(o1).get();
Object r2 = service.cacheFuture(o1).get();
Object r3 = service.cacheFuture(o1).get();

assertSame(r1, r2);
assertSame(r1, r3);
}

public void testEvict(CacheableService<?> service) throws Exception {
Object o1 = new Object();

Expand Down Expand Up @@ -450,6 +461,11 @@ public void testCacheable() throws Exception {
testCacheable(cs);
}

@Test
public void testCacheableFuture() throws Exception {
testCacheableFuture(cs);
}

@Test
public void testInvalidate() throws Exception {
testEvict(cs);
Expand Down Expand Up @@ -510,6 +526,11 @@ public void testClassCacheCacheable() throws Exception {
testCacheable(ccs);
}

@Test
public void testClassCacheCacheableFuture() throws Exception {
testCacheableFuture(ccs);
}

@Test
public void testClassCacheInvalidate() throws Exception {
testEvict(ccs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

package org.springframework.cache.config;

import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.scheduling.annotation.AsyncResult;

/**
* @author Costin Leau
Expand All @@ -40,6 +42,11 @@ public Object cache(Object arg1) {
return counter.getAndIncrement();
}

@Override
public Future<Object> cacheFuture(Object arg1) {
return new AsyncResult<>(counter.getAndIncrement());
}

@Override
public Object conditional(int field) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.cache.config;

import java.util.concurrent.Future;

/**
* Basic service interface.
*
Expand All @@ -27,6 +29,8 @@ public interface CacheableService<T> {

T cache(Object arg1);

Future<T> cacheFuture(Object arg1);

void invalidate(Object arg1);

void evictEarly(Object arg1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.scheduling.annotation.AsyncResult;

import java.util.concurrent.Future;

/**
* Simple cacheable service
Expand All @@ -41,6 +44,12 @@ public Long cache(Object arg1) {
return counter.getAndIncrement();
}

@Override
@Cacheable("testCache")
public Future<Long> cacheFuture(Object arg1) {
return new AsyncResult<>(counter.getAndIncrement());
}

@Override
@CacheEvict("testCache")
public void invalidate(Object arg1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<cache:advice id="cacheAdviceInterface" cache-manager="cacheManager">
<cache:caching cache="testCache">
<cache:cacheable method="cache"/>
<cache:cacheable method="cacheFuture"/>
<cache:cacheable method="conditional" condition="#classField == 3"/>
<cache:cacheable method="unless" unless="#result > 10"/>
<cache:cacheable method="key" key="#p0"/>
Expand Down Expand Up @@ -61,6 +62,7 @@
<cache:cacheable method="nam*" key="#root.methodName + #root.caches[0].name"/>
<cache:cacheable method="rootVars" key="#root.methodName + #root.method.name + #root.targetClass + #root.target"/>
<cache:cacheable method="cache"/>
<cache:cacheable method="cacheFuture"/>
<cache:cacheable method="conditional"/>
<cache:cacheable method="unless"/>
<cache:cacheable method="null*"/>
Expand Down

0 comments on commit 48329ff

Please sign in to comment.