前面讲了理论部分,现在开始具体运用。
需求:通过在方法加@MyAnnotation自动实现,从缓存取,若没有就从别的地方取值,然后再入缓存。
- 自定义注解MyAnnotation
/**
* Created by King on 2017/8/30.
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
String key();
String hashKey();
ValueType valueType();
}
ValueType:是一个枚举类,定义了redis缓存的数据类型
- 目标方法
@MyAnnotation(key="aaaaaaaaaaabbb",valueType = ValueType.Hash,hashKey = "11111111")
public List<String> searchType11(Integer a) {
List<String> list = Lists.newArrayList();
//type为null,则查询所有
list.add("执行Controller方法,为了测试22222222222");
return list;
}
- 切面Aspect
@Aspect
@Component
public class ShiliAspect {
private static final Logger logger = LoggerFactory.getLogger(ShiliAspect.class);
@Autowired
RedisTemplate redisTemplate;
@Pointcut("@annotation(com.cci.market.security.aop.MyAnnotation)")
public void save(){
}
@Around("save()")
public Object addOperateLog(ProceedingJoinPoint pjp) throws Throwable {
//获取目标方法的名字
String methodName = pjp.getSignature().getName();
//获取目标方法
Method method = getMethod(pjp);
//获取方法的注解
MyAnnotation cacheable = method.getAnnotation(MyAnnotation.class);
Object returnObj = null;
if (cacheable.valueType().equals(ValueType.Map)){
//取缓存
Map<String, Object> map = redisTemplate.opsForHash().entries(cacheable.key());
if (map != null && map.size()>0) {
map.put("AOP","这是从缓存去的");
map.put("cacheable.name()",cacheable.key());
return map;
}
} else if (cacheable.valueType().equals(ValueType.Hash)){
returnObj = redisTemplate.opsForHash().get(cacheable.key(),cacheable.hashKey());
if (returnObj != null) {
return returnObj;
}
}
try{
//获取到返回值
returnObj = pjp.proceed(pjp.getArgs());
//入缓存
if (cacheable.valueType().equals(ValueType.Map)){
redisTemplate.opsForHash().putAll(cacheable.key(), (Map) returnObj);
} else if (cacheable.valueType().equals(ValueType.Hash)){
redisTemplate.opsForHash().put(cacheable.key(),cacheable.hashKey(),returnObj);
}
//设置时间
redisTemplate.expire(cacheable.key(), 10, TimeUnit.SECONDS);
}catch (Exception e){
logger.error(e.getMessage(),e);
}
return returnObj;
}
public static Method getMethod(ProceedingJoinPoint pjp) {
//获取目标方法参数值
Object[] args = pjp.getArgs();
//获取目标参数值的类型
Class[] argTypes = new Class[pjp.getArgs().length];
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
argTypes[i] = args[i].getClass();
}
}
Method method = null;
try {
//获取目标方法
method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return method;
}
}
改进:如果目标方法参数类型是int,long等,通过上述方法获取参数类型,直接变成了相应封装类。再根据方法名和参数类型去获取目标方法,会找不到。
其实获取目标方法有更加简单方法:
**//获取目标方法
Method method = ((MethodSignature) pjp.getSignature()).getMethod();**