Skip to content

Commit

Permalink
refactor(cache): supports specifying the cache type and expiration ti…
Browse files Browse the repository at this point in the history
…me for a single method container or custom container (Gitee#I8UZSO)
  • Loading branch information
Createsequence committed Jan 11, 2024
1 parent de4dfb0 commit ce0ec88
Show file tree
Hide file tree
Showing 33 changed files with 1,248 additions and 605 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,53 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
* If a method has been annotated by {@link ContainerMethod},
* upgrade it to a cacheable container.
* <p>An annotation to mark a container as cacheable.<br />
* It can be used on a method which annotated by {@link ContainerMethod},
* or a class which implements {@link cn.crane4j.core.container.Container} interface.
*
* <p>The actual cache implementation is determined by what cache manager is specified in the annotation,
* when container is created, the cache factory will be used to create a cache instance,
* and wrap the container with {@link cn.crane4j.core.cache.CacheableContainer}.
*
* @author huangchengxing
* @see ContainerMethod
* @see cn.crane4j.core.cache.CacheManager
* @see cn.crane4j.core.cache.CacheableContainerProcessor
* @see cn.crane4j.core.support.container.CacheableMethodContainerFactory
* @see cn.crane4j.core.support.container.ContainerMethodAnnotationProcessor
*/
@Documented
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ContainerCache {

// TODO supprot specified cache manager and expire time
/**
* The name of the cache manager
*
* @return cache manager name
* @see cn.crane4j.core.cache.CacheManager
*
* @since 2.4.0
*/
String cacheManager() default "";

/**
* The time to live of the cache,
* default to -1L, which means the cache will never proactive evict.
*
* @return time to live
* @since 2.4.0
*/
long expirationTime() default -1L;

/**
* The cache name, when empty, defaults to {@link ContainerMethod#namespace()} of the marked method.
* The time unit of the cache expiry time,
* default to {@link TimeUnit#MILLISECONDS}.
*
* @return cache name
* @return time unit
* @since 2.4.0
*/
String cacheName() default "";
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package cn.crane4j.core.cache;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
* Abstract cache manager.
*
* @author huangchengxing
* @since 2.4.0
*/
public abstract class AbstractCacheManager implements CacheManager {

private final ConcurrentMap<String, AbstractCacheObject<?>> caches = new ConcurrentHashMap<>();

/**
* Get cache instance by name,
* if cache instance still not created by {@link #createCache}, return null.
*
* @param name cache name
* @return cache instance
*/
@SuppressWarnings("unchecked")
@Nullable
@Override
public <K> CacheObject<K> getCache(String name) {
return (CacheObject<K>) caches.get(name);
}

/**
* Create cache instance, if cache instance already created,
* remove the old cache instance and create a new cache instance.
*
* @param name cache name
* @param expireTime expire time
* @param timeUnit time unit
* @return cache instance
*/
@SuppressWarnings("unchecked")
@NonNull
@Override
public <K> CacheObject<K> createCache(
String name, Long expireTime, TimeUnit timeUnit) {
AbstractCacheObject<Object> cacheObject = doCreateCache(name, expireTime, timeUnit);
AbstractCacheObject<?> old = caches.put(name, cacheObject);
if (Objects.nonNull(old)) {
invalidate(old);
}
return (CacheObject<K>)cacheObject;
}


/**
* Remove cache.
*
* @param name cache name
* @see CacheObject#isInvalid()
* @see CacheObject#clear()
*/
@Override
public void removeCache(String name) {
caches.computeIfPresent(name, (k, v) -> {
invalidate(v);
return null;
});
}

/**
* Clear all cache.
*/
@Override
public void clearAll() {
List<AbstractCacheObject<?>> allCaches = new ArrayList<>(caches.values());
caches.clear();
allCaches.forEach(this::invalidate);
}

/**
* Create cache instance.
*
* @param name cache name
* @param expireTime expire time
* @param timeUnit time unit
* @return cache instance
*/
@NonNull
protected abstract <K> AbstractCacheObject<K> doCreateCache(String name, Long expireTime, TimeUnit timeUnit);

/**
* Invalidate cache.
*
* @param cacheObject cache object
*/
protected void invalidate(AbstractCacheObject<?> cacheObject) {
cacheObject.setInvalid(true);
cacheObject.clear();
}

/**
* Abstract cache object.
*
* @param <K> key type
* @author huangchengxing
* @since 2.4.0
*/
@Getter
@RequiredArgsConstructor
protected abstract static class AbstractCacheObject<K> implements CacheObject<K> {
@Setter
private volatile boolean invalid = false;
private final String name;
}
}
59 changes: 0 additions & 59 deletions crane4j-core/src/main/java/cn/crane4j/core/cache/Cache.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cn.crane4j.core.cache;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.concurrent.TimeUnit;

/**
* Definition of cache.
*
* @author huangchengxing
* @since 2.4.0
*/
public interface CacheDefinition {

/**
* Get the name of this cache.
*
* @return cache name
*/
String getName();

/**
* Get the cache factory name
*
* @return cache factory name
* @see CacheManager
*/
@Nullable
String getCacheManager();

/**
* Get the expiry time of this cache.
*
* @return expire time
*/
Long getExpireTime();

/**
* Get the time unit of this cache.
*
* @return time unit
*/
TimeUnit getTimeUnit();

/**
* <p>Implementation of {@link CacheDefinition}.
*
* @author huangchengxing
* @since 2.4.0
*/
@Getter
@RequiredArgsConstructor
class Impl implements CacheDefinition {
private final String name;
private final String cacheManager;
private final Long expireTime;
private final TimeUnit timeUnit;
}
}
59 changes: 45 additions & 14 deletions crane4j-core/src/main/java/cn/crane4j/core/cache/CacheManager.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,61 @@
package cn.crane4j.core.cache;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.concurrent.TimeUnit;

/**
* Cache manager.
* {@link CacheObject} manager.
*
* @author huangchengxing
* @see Cache
* @see ConcurrentMapCacheManager
* @see CacheObject
* @see GuavaCacheManager
* @see MapCacheManager#newWeakConcurrentMapCacheManager()
* @see MapCacheManager#newConcurrentHashMapCacheManager()
* @since 2.4.0
*/
public interface CacheManager {

String DEFAULT_MAP_CACHE_MANAGER_NAME = "WeakConcurrentHashMapCacheFactory";
String DEFAULT_GUAVA_CACHE_MANAGER_NAME = "GuavaCacheManager";

/**
* <p>Delete the corresponding cache if it already exists.<br />
* The {@link Cache#isExpired()} of a deleted cache object must return false.
* Create cache instance, if cache instance already created,
* remove the old cache instance and create a new cache instance.
*
* @param cacheName cache name
* @param name cache name
* @param expireTime expire time
* @param timeUnit time unit
* @param <K> key type
* @return cache instance
*/
void removeCache(String cacheName);
@NonNull
<K> CacheObject<K> createCache(String name, Long expireTime, TimeUnit timeUnit);

/**
* <p>Get cache, if it does not exist create it first.<br />
* The obtained cache is <b>not always</b> guaranteed to be valid,
* caller needs to ensure the timeliness of the cache itself through {@link Cache#isExpired()}.
* Get cache instance by name,
* if cache instance still not created by {@link #createCache}, return null.
*
* @param cacheName cache name
* @param <K> key type
* @return cache object
* @param name cache name
* @return cache instance
*/
@Nullable
<K> CacheObject<K> getCache(String name);

/**
* <p>Remove cache.<br />
* When a cache is removed, manager will call {@link CacheObject#clear()} to clear the cache,
* and mark the cache as invalid by {@link CacheObject#isInvalid()}.
*
* @param name cache name
* @see CacheObject#isInvalid()
* @see CacheObject#clear()
*/
void removeCache(String name);

/**
* Clear all cache.
*/
<K> Cache<K> getCache(String cacheName);
void clearAll();
}
Loading

0 comments on commit ce0ec88

Please sign in to comment.