SearchCacheAspect.java 5.54 KB
package com.yoho.search.aop.cache;

import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.cache.CacheType;
import com.yoho.search.cache.beans.SearchCacheFactory;
import com.yoho.search.cache.model.SearchCache;
import com.yoho.search.common.utils.HttpServletRequestUtils;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.cache.beans.SearchCacheService;

@Component
@Aspect
@Order(Integer.MAX_VALUE-1)
public class SearchCacheAspect {

	@Autowired
	private SearchCacheService searchCacheService;
	@Autowired
	private SearchCacheFactory searchCacheFactory;

	@Around("@annotation(com.yoho.search.aop.cache.SearchCacheAble)")
	public Object doCache(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature signature = (MethodSignature) pjp.getSignature();
		// 检查注解
		SearchCacheAble searchCacheAble = signature.getMethod().getAnnotation(SearchCacheAble.class);
		if (searchCacheAble == null) {
			return pjp.proceed();
		}
		// 检查返回类型
		Class<? extends Serializable> returnClass = this.getReturnClass(searchCacheAble, signature);
		if (returnClass == null) {
			return pjp.proceed();
		}
		// 检查cacheKey
		RedisKeyBuilder redisKeyBuilder = this.getRedisKeyBuilder(pjp, searchCacheAble);
		if (StringUtils.isBlank(redisKeyBuilder.getKey())){
			return pjp.proceed();
		}
		SearchCache searchCache = searchCacheFactory.getAspectSearhCache(searchCacheAble);
		boolean useJsonSerializable = searchCacheAble.cacheType().equals(CacheType.EHCACHE)?false:true;
		Serializable cacheObject = searchCacheService.getSerializableObjectFromCache(searchCache, redisKeyBuilder, returnClass,useJsonSerializable);

		if (cacheObject != null) {
			return cacheObject;
		}
		Object result = pjp.proceed();
		if (result == null) {
			return result;
		}
		cacheObject = (Serializable) result;

		if (cacheObject instanceof SearchApiResult && ((SearchApiResult) cacheObject).getCode() != 200) {
			return cacheObject;
		}
		searchCacheService.addSerializableObjectToCache(searchCache, redisKeyBuilder, cacheObject,useJsonSerializable);
		return cacheObject;
	}

	// 校验返回类型是否一致
	private Class<? extends Serializable> getReturnClass(SearchCacheAble searchCacheAble, MethodSignature signature) {
		final Class<?> returnType = signature.getMethod().getReturnType();
		final Class<? extends Serializable> returnClass = searchCacheAble.returnClass();
		if (!returnType.getName().equals(returnClass.getName())) {
			return null;
		}
		return returnClass;
	}

	// 获取请求的参数
	private RedisKeyBuilder getRedisKeyBuilder(ProceedingJoinPoint pjp, SearchCacheAble searchCacheAble) {
		Object[] arges = pjp.getArgs();
		Object object = arges[0];
		if (object instanceof ISearchCacheAbleParam) {
			return this.getRedisKeyBuilder((ISearchCacheAbleParam) object, searchCacheAble);
		}
		if (object instanceof HttpServletRequest) {
			return this.getRedisKeyBuilder((HttpServletRequest) object, searchCacheAble);
		}
		if (object instanceof Map) {
			return this.getRedisKeyBuilder((Map<?, ?>) object, searchCacheAble);
		}
		return null;
	}

	// 获取SearchCacheAbleParam的缓存key
	private RedisKeyBuilder getRedisKeyBuilder(ISearchCacheAbleParam searchCacheAbleParam, SearchCacheAble searchCacheAble) {
		String valueString = searchCacheAbleParam.toCacheKeyValue();
		return this.getRedisKeyBuilderByParamKey(valueString, searchCacheAble);
	}
	
	// 获取httpServletRequest的缓存key
	private RedisKeyBuilder getRedisKeyBuilder(HttpServletRequest httpServletRequest, SearchCacheAble searchCacheAble) {
		Map<String, String> paramMap = HttpServletRequestUtils.transParamType(httpServletRequest);
		return this.getRedisKeyBuilder(paramMap, searchCacheAble);
	}
	
	// 获取请求的参数
	private RedisKeyBuilder getRedisKeyBuilder(Map<?, ?> paramMap, SearchCacheAble searchCacheAble) {
		List<String> includeParams = Arrays.asList(searchCacheAble.includeParams());
		List<String> excludeParams = Arrays.asList(searchCacheAble.excludeParams());
		String paramKey = "";
		if (!includeParams.isEmpty()) {
			paramKey = HttpServletRequestUtils.genParamStringWithIncludeParams(paramMap, includeParams);
		} else if (!excludeParams.isEmpty()) {
			paramKey = HttpServletRequestUtils.genParamStringWithExcludeParams(paramMap, excludeParams);
		} else {
			paramKey = HttpServletRequestUtils.genParamString(paramMap);
		}
		return this.getRedisKeyBuilderByParamKey(paramKey, searchCacheAble);
	}

	private RedisKeyBuilder getRedisKeyBuilderByParamKey(String paramKey,SearchCacheAble searchCacheAble){
		RedisKeyBuilder redisKeyBuilder = RedisKeyBuilder.newInstance();
		redisKeyBuilder.appendFixed("YOHOSEARCH:AOP:");
		redisKeyBuilder.appendFixed(searchCacheAble.cacheName()).appendFixed(":");
		if(searchCacheAble.needMd5()){
			redisKeyBuilder.appendVar(MD5Util.string2MD5(paramKey));
		}else{
			redisKeyBuilder.appendVar(paramKey);
		}
		return redisKeyBuilder;
	}
}