AbstractCacheComponent.java 5.05 KB
package com.yoho.search.cache.beans;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.cache.impls.EhCache;
import com.yoho.search.cache.impls.SearchRedis;
import com.yoho.search.cache.model.CacheObject;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.utils.SearchParamUtils;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class AbstractCacheComponent<T> {

    @Autowired
    private EhCache ehCache;
    @Autowired
    private SearchRedis searchRedis;

    public T queryWithCache(SearchParam searchParam, @Nullable Object... params) throws Exception {
        //1、生成RedisKeyBuilder
        RedisKeyBuilder redisKeyBuilder = this.genRedisKeyBuilder(searchParam, params);
        if (redisKeyBuilder == null) {
            return null;
        }
        //2、取本地缓存,缓存命中,则直接返回
        T result = this.getValueFromEhcache(redisKeyBuilder);
        if (result != null) {
            return result;
        }
        //3、取redis缓存,缓存命中,则回写ehcahce
        result = this.getValueFromRedis(redisKeyBuilder);
        if (result != null) {
            this.addValueToEhcache(redisKeyBuilder, result);
            return result;
        }
        return this.doInnerQuery(redisKeyBuilder, searchParam, params);
    }

    private T doInnerQuery(RedisKeyBuilder redisKeyBuilder, SearchParam searchParam, @Nullable Object... params) throws Exception {
        T result = this.doRealQuery(searchParam, params);
        if (result == null) {
            return result;
        }
        this.addValueToEhcache(redisKeyBuilder, result);
        this.addValueToRedis(redisKeyBuilder, result);
        return result;
    }

    protected abstract T doRealQuery(SearchParam searchParam, @Nullable Object... params) throws Exception;

    private T getValueFromEhcache(RedisKeyBuilder redisKeyBuilder) throws Exception {
        if (!useEhcache()) {
            return null;
        }
        CacheObject cacheObject = ehCache.get(redisKeyBuilder);
        if (cacheObject != null) {
            Object object = cacheObject.toObject();
            return (T) object;
        }
        return null;
    }

    private void addValueToEhcache(RedisKeyBuilder redisKeyBuilder, T result) {
        if (!useEhcache()) {
            return;
        }
        ehCache.addOrUpdate(redisKeyBuilder, new CacheObject(result), this.cacheTimeInMinute());
    }

    private void addValueToRedis(RedisKeyBuilder redisKeyBuilder, T result) {
        if (!useRedis()) {
            return;
        }
        String jsonString = JSON.toJSONString(result, SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect);
        CacheObject toCacheResult = new CacheObject(jsonString);
        searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInMinute());
    }

    private T getValueFromRedis(RedisKeyBuilder redisKeyBuilder) {
        if (!useRedis()) {
            return null;
        }
        CacheObject cacheObject = searchRedis.get(redisKeyBuilder);
        if (cacheObject == null || cacheObject.getValue() == null) {
            return null;
        }
        if (!(cacheObject.getValue() instanceof String)) {
            return null;
        }
        String redisValue = (String) cacheObject.toObject();
        Type superClass = getClass().getGenericSuperclass();
        Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
        return JSON.parseObject(redisValue, type);
    }

    protected abstract int cacheTimeInMinute();

    protected abstract String cacheSceneKey();

    protected RedisKeyBuilder defaultRedisKeyBuilder() {
        RedisKeyBuilder redisKeyBuilder = RedisKeyBuilder.newInstance();
        redisKeyBuilder.appendFixed("YOHOSEARCH");//前缀
        redisKeyBuilder.appendFixed(":").appendFixed(cacheSceneKey());//场景
        redisKeyBuilder.appendFixed(":").appendFixed(cacheTimeInMinute());//缓存时间
        return redisKeyBuilder;
    }

    protected RedisKeyBuilder genRedisKeyBuilder(SearchParam searchParam,  @Nullable Object... params) {
        RedisKeyBuilder redisKeyBuilder = defaultRedisKeyBuilder();
        if (searchParam != null) {
            SearchSourceBuilder searchSourceBuilder = SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam);
            redisKeyBuilder.appendFixed(":").appendVar(MD5Util.string2MD5(searchSourceBuilder.toString()));//报文
        }
        return redisKeyBuilder;
    }

    protected boolean useEhcache() {
        return false;
    }

    protected boolean useRedis() {
        return true;
    }

}