参考文章:http://blog.csdn.net/zhanngle/article/details/41077423
1:注解
1:标注在方法上的注解,让spring可以找到将哪个方法的参数当做key,返回值当做value
package com.fengyong.base.beans.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类描述:
*
* @author fengyong
* @version 1.0
* @since 1.0
* Created by fengyong on 16/9/30 下午5:25.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Cacheable {
public enum KeyMode{
CACHEKEY, //只有加了@CacheKey的参数,才加入key后缀中
BASIC, //只有基本类型参数,才加入key后缀中,如:String,Integer,Long,Short,Boolean
ALL; //所有参数都加入key后缀
}
public String key() default ""; //缓存key
public KeyMode keyMode() default KeyMode.ALL; //key的后缀模式
public int expire() default 0; //缓存多少秒,默认无限期
}
2:标注在参数上的注解
package com.fengyong.base.beans.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类描述:
*
* @author fengyong
* @version 1.0
* @since 1.0
* Created by fengyong on 16/9/30 下午5:28.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface CacheKey {
}
2:AOP配置
<bean id="redisCacheAop" class="com.system.aop.RedisCacheAop"></bean>
<aop:config>
<!-- 后置通知 -->
<aop:aspect ref="redisCacheAop">
<aop:around method="cached" pointcut="@annotation(cache))" ></aop:around>
</aop:aspect>
</aop:config>
3:AOP类
package com.system.aop;
import com.fengyong.base.beans.Po;
import com.fengyong.base.beans.annotation.CacheKey;
import com.fengyong.base.beans.annotation.Cacheable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
/**
* 类描述:
*
* @author fengyong
* @version 1.0
* @since 1.0
* Created by fengyong on 16/10/1 上午8:48.
*/
public class RedisCacheAop {
@Autowired
private RedisTemplate redisTemplate;
//@Around("@annotation(cache)") 可用配置代替pointcut="@annotation(cache))"
public Object cached(final ProceedingJoinPoint pjp, Cacheable cache) throws Throwable {
String key = getCacheKey(pjp, cache);
ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
Object value = valueOper.get(key); //从缓存获取数据
if (value != null) return value; //如果有数据,则直接返回
value = pjp.proceed(); //跳过缓存,到后端查询数据
if (cache.expire() <= 0) { //如果没有设置过期时间,则无限期缓存
valueOper.set(key, value);
} else { //否则设置缓存时间
valueOper.set(key, value, cache.expire(), TimeUnit.SECONDS);
}
return value;
}
/**
* 获取缓存的key值
*
* @param pjp
* @param cache 注解
* @return
*/
private String getCacheKey(ProceedingJoinPoint pjp, Cacheable cache) throws Exception {
StringBuilder buf = new StringBuilder();
buf.append(pjp.getSignature().getDeclaringTypeName()).append(".").append(pjp.getSignature().getName());//获取包名,类名,方法名
if (cache.key().length() > 0)
buf.append(".").append(cache.key());//额外添加的key,,防止有重复的key
Object[] args = pjp.getArgs();
if (cache.keyMode() == Cacheable.KeyMode.CACHEKEY) {
//Annotation[][] pas=((MethodSignature)pjp.getSignature()).getMethod().getParameterAnnotations(); //这里获取的可能是代理对象,所以拿不到注解对象
Annotation[][] pas = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(),
((MethodSignature) pjp.getSignature()).getParameterTypes()).getParameterAnnotations();
for (int i = 0; i < pas.length; i++) {
for (Annotation an : pas[i]) {
if (an instanceof CacheKey) {
getAllKey(buf, args[i]);
break;
}
}
}
} else if (cache.keyMode() == Cacheable.KeyMode.BASIC) {
for (Object arg : args)
getBasicKey(buf, arg);
} else if (cache.keyMode() == Cacheable.KeyMode.ALL) {
for (Object arg : args)
getAllKey(buf, arg);
}
return buf.toString();
}
/**
* po实体类
*
* @param buf
* @param arg
* @throws IllegalAccessException
*/
private void getAllKey(StringBuilder buf, Object arg) throws IllegalAccessException {
if (arg instanceof Po)
buf.append(".").append(((Po) arg).cacheString());
else
buf.append(".").append(arg.toString());
}
/**
* 基本类型
*
* @param buf
* @param arg
*/
private void getBasicKey(StringBuilder buf, Object arg) {
if (arg instanceof String) {
buf.append(".").append(arg);
} else if (arg instanceof Integer || arg instanceof Long || arg instanceof Short) {
buf.append(".").append(arg.toString());
} else if (arg instanceof Boolean) {
buf.append(".").append(arg.toString());
}
}
}
4:PO类
注:所有的javabean都继承po类
package com.fengyong.base.beans;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import java.io.Serializable;
import java.lang.reflect.Field;
/**
* 类描述:
*
* @author fengyong
* @version 1.0
* @since 1.0
* Created by fengyong on 16/7/29 上午11:28.
*/
public class Po extends BaseBean implements Serializable {
private static final long serialVersionUID = 3741866100111444587L;
/**
* 拷贝对象
* @param po
* @param <T>
* @return
*/
public <T extends Po> T fromPo(Po po) {
BeanUtils.copyProperties(po, this);
return (T)this;
}
/**
* key的添加:属性值,引用类型判断null不添加,String判断null和""不添加
* @return
* @throws IllegalAccessException
*/
public String cacheString() throws IllegalAccessException {
return cacheString(null);
}
/**
*
* @param attachedKey 该参数用于避免偶尔相同的cacheKey
* @return
* @throws IllegalAccessException
*/
public String cacheString(String attachedKey) throws IllegalAccessException {
StringBuffer sb = new StringBuffer();
if(StringUtils.isNotBlank(attachedKey))
sb.append(".").append(attachedKey).append(".");
sb.append(this.getClass().getSimpleName()).append("{");
Field[] fields = this.getClass().getDeclaredFields();
for(Field field:fields){
field.setAccessible(true);
if(field.get(this)!=null){
if(field.get(this) instanceof String){
if((field.get(this))!=""){
sb.append(field.getName()).append("=");
sb.append(field.get(this)).append(",");
}
}else{
sb.append(field.getName()).append("=");
sb.append(field.get(this)).append(",");
}
}
}
sb.deleteCharAt(sb.length()-1).append("}");
return sb.toString();
}
}
5:测试
1:被测试的service
@Cacheable(keyMode = Cacheable.KeyMode.CACHEKEY)
public ResultPoBean<BaseSysUserPo> getSysUserPo( Long sysUserPoId,@CacheKey BaseSysUserPo userPo,String str)
@Autowired
private UserService userService;
@Test
public void userServiceTest() throws LogicException {
Map<String,String> map = new HashMap<String, String>();
BaseSysUserPo baseSysUserPo = new BaseSysUserPo();
baseSysUserPo.setEmail("qq@163.com");
baseSysUserPo.setUserName("fengyongl");
ResultPoBean<BaseSysUserPo> resultPoBean = userService.getSysUserPo(new Long(320),baseSysUserPo,"测试参数");
}
3:测试结果,key的值
com.system.service.user.UserService.getSysUserPo.BaseSysUserPo{userName=fengyongl,email=qq@163.com}