public abstract class Api<K, V> {
/**
* 设置最大缓存个数
*/
int maximumSize = 2000;
/**
* 实例化缓存
*/
LoadingCache<K, V> cache;
/**
* 初始化缓存(1个参数)
*
* @param expire 过期时间
* @param function 1个参数
*/
public Api(long expire, Function<K, V> function) {
init(expire, function, null);
}
/**
* 初始化缓存(2个以上的参数)
*
* @param expire 过期时间
* @param biFunction 传入2个以上的参数
*/
public Api(long expire, BiFunction<String, String, V> biFunction) {
init(expire, null, biFunction);
}
/**
* 初始化缓存
*
* @param expire 数据过期时间的值
* @param function 传入函数
* @param biFunction 传入多个参数
*/
private LoadingCache<K, V> init(long expire, Function<K, V> function, BiFunction<String, String, V> biFunction) {
Caffeine<Object, Object> cacheBuilder = Caffeine.newBuilder();
// 基于大小-缓存大小,缓存最大条数,超过这个条数就是驱逐缓存
cacheBuilder.maximumSize(maximumSize);
// 这个参数是 LoadingCache 和 AsyncLoadingCache 的才会有的。在刷新的时候如果查询缓存元素,其旧值将仍被返回,直到该元素的刷新完毕后结束后才会返回刷新后的新值。
// refreshAfterWrite 将会使在写操作之后的一段时间后允许 key 对应的缓存元素进行刷新,但是只有在这个 key 被真正查询到的时候才会正式进行刷新操作。
// 在刷新的过程中,如果抛出任何异常,会保留旧值。异常会被 logger 打印,然后被吞掉。
// 此外,CacheLoader 还支持通过覆盖重写 CacheLoader.reload(K, V) 方法使得在刷新中可以将旧值也参与到更新的过程中去。
// refresh 的操作将会异步执行在一个 Executor 上。默认的线程池实现是 ForkJoinPool.commonPool()。当然也可以通过覆盖 Caffeine.executor(Executor) 方法自定义线程池的实现。
// 这个 Executor 同时负责 removalListener 的操作。
cacheBuilder.refreshAfterWrite(expire, TimeUnit.SECONDS);
cache = cacheBuilder.build(
key -> {
V value = null;
if (null != function) {
value = function.apply(key);
}
if (biFunction != null) {
String[] args = ((String) key).split(",");
value = biFunction.apply(args[0], args[1]);
}
return value;
});
return cache;
}
/**
* 主动触发 loading
*
* @param key
*/
public void refresh(K key) {
try {
if (null != cache && null != cache.get(key)) {
cache.refresh(key);
}
} catch (Throwable ignore) {
log.error(">>>>>>>> query from caffeine cache by key: " + key + ", get a null <<<<<<<<<<<<<", ignore);
}
}
/**
* 根据 key 查询的公共方法,没有特殊需求的话,统一走此方法获取数据
*
* @param key
* @return
*/
public V get(K key) {
try {
if (null != cache) {
return cache.get(key);
}
return null;
} catch (Throwable e) {
log.error(">>>>>>>> query from caffeine cache by key: " + key + ", get a null <<<<<<<<<<<<<", e);
return null;
}
}
}
@Log4j2
public abstract class ApiCache {
public class Api0 extends Api {
public Api0(long expire, Function<String, ?> function) {
super(expire, function);
}
public Api0(long expire, BiFunction<String, String, ?> biFunction) {
super(expire, biFunction);
}
}
private Map<String, Api0> apis = new HashMap<>();
protected void put(String cacheName, Function<String, ?> function,Long expire) {
apis.put(cacheName, new Api0(expire, function));
}
protected void put(String cacheName, BiFunction<String, String, ?> function,Long expire) {
apis.put(cacheName, new Api0(expire, function));
}
/**
* @param type 业务类型 api key
* @param key 缓存数据 key
* @param returnClass 返回值类型
* @param <V>
* @return
*/
public <V> V get(String type, String key, Class<V> returnClass) {
//log.info(">>>>>>>>invoker:[" + "" + "] Caffeine get by key: " + key + " <<<<<<<<<<<<<" + UUID.randomUUID().toString());
try {
Api0 api01 = apis.get(type);
if(null != api01){
Object o = api01.get(key);
return (V) o;
}
} catch (Throwable ignore) {
log.error("ApiCache get error"+ ignore.getMessage(),ignore);
}
return null;
}
/**
* 用于调试
*
* @return
*/
public Map<String, Api0> getApis() {
return apis;
}
public void refresh(String type, String key) {
//log.info(">>>>>>>> api wrapper type:" + type + "] Caffeine cache has been refreshed by key: " + key + " <<<<<<<<<<<<<");
try {
Api0 api01 = apis.get(type);
if(null != api01){
api01.refresh(key);
}
} catch (Throwable ignore) {
log.error("ApiCache refresh error"+ ignore.getMessage(),ignore);
}
}
}
@Component
@Order(value = 5)
public class CacheUserCosplayDataWrapper extends ApiCache implements CommandLineRunner {
public static String USER_SELF_DATA_CACHE = "userSelfDataCache";
public static String USER_OTHER_DATA_CACHE = "userOtherDataCache";
@Autowired
private UserCosplayDataService cosplayDataService;
@Override
public void run(String... args) throws Exception {
//缓存设置 10秒超时
super.put(USER_SELF_DATA_CACHE, cosplayDataService::getUserSelfDataByUserId, 3L);
super.put(USER_OTHER_DATA_CACHE, cosplayDataService::getUserOtherDataByUserId, 3L);
}
}
public UserOtherDataResponse getUserOtherDataByUserId(String userIdInfo) {
List<String> userIds = Arrays.asList(userIdInfo.split("_"));
Long otherUserId = Long.valueOf(userIds.get(0));
UserOtherDataResponse response = new UserOtherDataResponse();
// 查询用户信息
CommonResult<UserBaseInfoResponse> userBaseInfoResult =
userBaseInfoFeign.getUserBaseDetailInfoByUserId(new UserBaseInfoRequest(otherUserId));
if (!userBaseInfoResult.getCode().equals(CommonResult.successResult().getCode())) {
throw new BusinessException("查询他的主页失败");
}
// 拷贝用户信息(优化为空时候不拷贝)
BeanUtil.copyProperties(userBaseInfoResult.getData(), response,
CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
return response;
}