All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commons.box.app.DataCache Maven / Gradle / Ivy

The newest version!
package commons.box.app;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import commons.box.app.func.DataConsumer;
import commons.box.app.func.DataFunction;
import commons.box.util.Maps;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Cache 实现 使用了 guava cache
 * 

* 此缓存具备序列化声明,避免目标应用因此对象而导致序列化失败。但序列化时不会序列化内部具体缓存内容,仅序列化缓存的配置选项。 */ public class DataCache implements Serializable { private final transient Cache> cache; private final Spec spec; private final DataFunction loader; private final DataConsumer> builderConfig; protected DataCache() { this(null, null, null); } public DataCache(@Nullable Spec spec) { this(spec, null, null); } public DataCache(@Nullable Spec spec, @Nullable DataFunction loader) { this(spec, loader, null); } public DataCache(@Nullable Spec spec, @Nullable DataFunction loader, @Nullable DataConsumer> builderConfig) { this.spec = spec; this.loader = loader; this.builderConfig = builderConfig; CacheBuilder cb = CacheBuilder.newBuilder(); if (this.spec != null) { if (spec.getMax() > 0) cb = cb.maximumSize(spec.getMax()); if (spec.getExpireAfterAccess() > 0) cb = cb.expireAfterAccess(spec.getExpireAfterAccess(), TimeUnit.MILLISECONDS); if (spec.getExpireAfterWrite() > 0) cb = cb.expireAfterWrite(spec.getExpireAfterWrite(), TimeUnit.MILLISECONDS); if (spec.getInitCapacity() > 0) cb = cb.initialCapacity(spec.getInitCapacity()); } if (this.builderConfig != null) this.builderConfig.accept(cb); this.cache = cb.build(); } private Object readResolve() { return new DataCache<>(this.spec, this.loader, this.builderConfig); } public static DataCache build() { return build(Spec.from(-1), null); } public static DataCache build(DataFunction loader) { return build(Spec.from(-1), loader); } public static DataCache build(long max) { return build(Spec.from(max)); } public static DataCache build(long max, long expireAfterAccess) { return build(Spec.from(max, expireAfterAccess), null, null); } public static DataCache build(long max, long expireAfterAccess, long expireAfterWrite) { return build(Spec.from(max, expireAfterAccess, expireAfterWrite)); } public static DataCache build(long max, DataFunction loader) { return build(Spec.from(max), loader); } public static DataCache build(long max, long expireAfterAccess, DataFunction loader) { return build(Spec.from(max, expireAfterAccess), loader, null); } public static DataCache build(long max, long expireAfterAccess, long expireAfterWrite, DataFunction loader) { return build(Spec.from(max, expireAfterAccess, expireAfterWrite), loader); } public static DataCache build(@Nullable Spec spec) { return build(spec, null, null); } public static DataCache build(@Nullable Spec spec, @Nullable DataFunction loader) { return build(spec, loader, null); } public static DataCache build(@Nullable Spec spec, @Nullable DataFunction loader, @Nullable DataConsumer> builderConfig) { return new DataCache<>(spec, loader, builderConfig); } @Nonnull protected SafeKey createKey(Object... param) { return new SafeKey(param); } @Nonnull protected SafeObject createEntry(Function supplier, Object... key) { return new SafeObject<>((supplier != null) ? supplier.apply(key) : null); } @Nonnull protected SafeObject createEntry(T value) { return new SafeObject<>(value); } @Nullable protected Object[] keyValue(SafeKey key) { return (key != null) ? key.objs() : null; } @Nullable protected T entryValue(SafeObject entry) { return (entry != null) ? entry.getObject() : null; } /** * 内部操作 cache * * @return */ protected Cache> cache() { return this.cache; } /** * 获取值,如果失败则调用loader重新获取值 *

* 只有当值存在或者已经声明了 loader 的情况下才会返回正确结果,否则返回空 * * @return */ public T get(Object... key) { try { return checkAndGet(key); } catch (Throwable ignored) { } return this.loader.apply(key); } /** * 与 get 方法相同,此处检查内部异常,如果存在异常则抛出 * * @param key * @return * @throws AppError */ public T checkAndGet(Object... key) throws AppError { if (key == null) throw AppError.error("不允许空的 key"); try { SafeKey k = this.createKey(key); SafeObject so = this.cache.getIfPresent(k); if (so != null) return this.entryValue(so); if (this.loader == null) return null; so = this.createEntry(this.loader.apply(key)); this.cache.put(k, so); return this.entryValue(so); } catch (Throwable e) { throw AppError.error("缓存获取值失败 key=" + Arrays.toString(key)); } } /** * 获取对应值,如果值未命中则使用 supplier 中的定义返回内容 *

* 与 guava cache 不同的是此处的 key 可能是参数化数组,为了写法上的方便将key值放置在后面 * * @param supplier * @param key * @return */ public T getOr(Function supplier, Object... key) { if (supplier == null) return this.get(key); try { return checkAndGetOr(supplier, key); } catch (Throwable ignored) { } return supplier.apply(key); } /** * 获取对应值 *

* 与 guava cache 不同的是此处的 key 可能是参数化数组,为了写法上的方便将key值放置在后面 * * @param supplier * @param key * @return * @throws AppError */ public T checkAndGetOr(Function supplier, Object... key) throws AppError { if (key == null) throw AppError.error("不允许空的 key"); if (supplier == null) return this.checkAndGet(key); try { SafeKey k = this.createKey(key); SafeObject so = this.cache.getIfPresent(k); if (so != null) return this.entryValue(so); so = this.createEntry(supplier.apply(key)); this.cache.put(k, so); return this.entryValue(so); } catch (Throwable e) { throw AppError.error("缓存获取值失败 key=" + Arrays.toString(key)); } } /** * 尝试获取 如果失败则返回 空 *

* 此方法不会调用内部 loader,仅根据当前快照直接返回值 * * @param key * @return */ public T getIfPresent(Object... key) { SafeObject val = this.cache.getIfPresent(this.createKey(key)); return (val != null) ? this.entryValue(val) : null; } /** * 放入新值 * * @param key * @param value */ public void put(Object[] key, T value) { this.cache.put(this.createKey(key), this.createEntry(value)); } /** * 放入新值 * * @param map */ public void putAll(Map map) { if (map == null) return; map.forEach(this::put); } public void refresh(Object... key) { if (key == null) return; this.cache.invalidate(this.createKey(key)); } public void refreshAll(Iterable keys) { if (keys == null) return; for (Object[] k : keys) this.refresh(k); } public void refreshAll() { this.cache.cleanUp(); this.cache.invalidateAll(); } public Map doAsMap() { ConcurrentMap> map = this.cache.asMap(); if (map == null) return Maps.immmap(); Map am = new LinkedHashMap<>(); map.forEach((k, v) -> { Object[] p = this.keyValue(k); if (p == null) return; T e = this.entryValue(v); if (e == null) return; am.put(p, e); }); return Maps.immmap(am); } /** * 用于类型转换 给定的 supplier 不会执行 仅作为类型判断 *

* 一般用于通用类型定义但需额外使用特定类型的 get 时需要 * * @param supplier * @param

* @return */ @SuppressWarnings("unchecked") @Nonnull public

DataCache

as(Supplier

supplier) { return (DataCache

) this; } /** * 用于类型转换 给定的 supplier 不会执行 仅作为类型判断 *

* 一般用于通用类型定义但需额外使用特定类型的 get 时需要 * * @param supplier * @param

* @return */ @SuppressWarnings("unchecked") @Nonnull public

DataCache

as(Function supplier) { return (DataCache

) this; } /** * 缓存特性 各特性值为-1时使用默认值 */ public static final class Spec implements Serializable { private final long max; private final long expireAfterAccess; private final long expireAfterWrite; private final int initCapacity; public Spec(long max) { this(max, -1, -1, -1); } public Spec(long max, long expireAfterAccess) { this(max, expireAfterAccess, -1, -1); } public Spec(long max, long expireAfterAccess, long expireAfterWrite) { this(max, expireAfterAccess, expireAfterWrite, -1); } public Spec(long max, long expireAfterAccess, long expireAfterWrite, int initCapacity) { this.max = max; this.expireAfterAccess = expireAfterAccess; this.expireAfterWrite = expireAfterWrite; this.initCapacity = initCapacity; } public static Spec from(long max) { return from(max, -1, -1, -1); } public static Spec from(long max, long expireAfterAccess) { return from(max, expireAfterAccess, -1, -1); } public static Spec from(long max, long expireAfterAccess, long expireAfterWrite) { return from(max, expireAfterAccess, expireAfterWrite, -1); } public static Spec from(long max, long expireAfterAccess, long expireAfterWrite, int initCapacity) { return new Spec(max, expireAfterAccess, expireAfterWrite, initCapacity); } public long getMax() { return max; } public long getExpireAfterAccess() { return expireAfterAccess; } public long getExpireAfterWrite() { return expireAfterWrite; } public int getInitCapacity() { return initCapacity; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy