1.首先自定义注解 :添加缓存

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Memcached {
// key的前缀 default=STATIC的可以使用OMS清理缓存
String prefix() default "STATIC_";
// key
String key() default "";
// 过滤
String conditions() default "true";
// 緩存分組
String group() default "hos-portal-mclient1";
// 缓存有效期 2天 单位s
int expiration() default 60 * 60 * 48;
}
2.切面类

@Aspect
public class MemCachedAop {

private static final Logger log = LoggerFactory.getLogger(MemCachedAop.class);

@Value("${enable.static.cache}")
private boolean enableCache;

@Pointcut("execution(* com.ylzinfo.hospital.portal.service.appservice.*.*.*(..))")
protected void appservicePointcut(){}

@Autowired
private ICacheClient cacheClient;

/**
* 写入或者读取缓存
* 仅针对有注解的且该包下的方法
*/
@Around("(@annotation(memcached) && appservicePointcut())")
public Object doMemcachedAround(ProceedingJoinPoint call, Memcached memcached) throws Throwable {
String packageName = call.getSignature().getDeclaringTypeName();
String methodName = call.getSignature().getName();
log.info("执行方法: {} -> {}", packageName, methodName);
//返回最终结果
Object result = null;
//校验conditions
if (null != memcached
&& checkConditions(call,memcached.conditions())
&& enableCache) {
String key = resolvingKey(call,memcached.prefix(),memcached.key());
String group = memcached.group();
result = cacheClient.get(group, key);
if (null == result) {
// memcached中不存在
try {
//执行aop拦截的方法
result = call.proceed();
//获取注解配置memcached过期时间
int expiration = memcached.expiration();
cacheClient.put(group, key, result, expiration);
log.info("\n【写入Memcached缓存】" +
"\ngroup={}" +
"\nkey={}" +
"\nvalue={}" +
"\nexpiration={}",group,key, JSON.toJSON(result),expiration);
} catch (Throwable e) {
log.error("执行方法失败: {} -> {}", packageName, methodName);
log.error("失败原因:{}",e.getMessage());
}
}else{
// memcached中存在 直接返回
log.info("\n【读取Memcached缓存】" +
"\ngroup={}" +
"\nkey={}" +
"\nvalue={}",group,key,JSON.toJSON(result));
}
}else {
try {
result = call.proceed();
} catch (Throwable e) {
log.error("执行方法失败: {} -> {}", packageName, methodName);
log.error("失败原因:{}",e.getMessage());
}
}
return result;
}

/**
* 获取缓存的key
* key 定义在注解上,支持SPEL表达式
* @param key
* @param method
* @param args
* @return
*/
private String parseKey(String key, Method method, Object [] args){

//获取被拦截方法参数名列表(使用Spring支持类库)
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
String [] paraNameArr=u.getParameterNames(method);
//使用SPEL进行key的解析
ExpressionParser parser = new SpelExpressionParser();
//SPEL上下文
StandardEvaluationContext context = new StandardEvaluationContext();
//把方法参数放入SPEL上下文中
for(int i=0;i<paraNameArr.length;i++){
context.setVariable(paraNameArr[i], args[i]);
}
return parser.parseExpression(key).getValue(context,String.class);
}

/**
* 获取被拦截方法对象
*
* MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
* 而缓存的注解在实现类的方法上
* 所以应该使用反射获取当前对象的方法对象
*/
public Method getMethod(ProceedingJoinPoint pjp){
//获取参数的类型
Object [] args=pjp.getArgs();
Class [] argTypes=new Class[pjp.getArgs().length];
for(int i=0;i<args.length;i++){
argTypes[i]=args[i].getClass();
}
Method method=null;
try {
method=pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(),argTypes);
} catch (NoSuchMethodException e) {
log.error(e.getMessage());
} catch (SecurityException e) {
log.error(e.getMessage());
}
return method;
}

/**
* 解析key
* @author zengfanqi
* @date 2019/5/6
* @param
* @return String
*/
public String resolvingKey(ProceedingJoinPoint call,String prefix,String key){

//如果key为空直接将方法名称作为key
String methodName = call.getSignature().getName();
if(StringUtils.isEmpty(key)){
return prefix + methodName;
}

//判断key是否是spel表达式
if(key.startsWith("#")){
Method method=getMethod(call);
String parsekey = parseKey(key,method,call.getArgs());
if(StringUtils.isEmpty(parsekey)){
parsekey = methodName;
}
key = prefix+parsekey;
}else{
key = prefix+key;
}
return key;
}

/**
* 校验conditions
* @author zengfanqi
* @date 2019/5/6
* @param
* @return
*/
public boolean checkConditions(ProceedingJoinPoint call,String conditions){
boolean flag = false;
Method method=getMethod(call);
String condition = parseKey(conditions,method,call.getArgs());
if("true".equals(condition)){
flag = true;
}
return flag;
}
}
---------------------

AOP注解形式 整合memcache的更多相关文章

  1. Spring AOP注解形式简单实现

    实现步骤: 1:导入类扫描的注解解析器 命名空间:xmlns:context="http://www.springframework.org/schema/context" xsi ...

  2. Spring 通过XML配置文件以及通过注解形式来AOP 来实现前置,环绕,异常通知,返回后通知,后通知

    本节主要内容: 一.Spring 通过XML配置文件形式来AOP 来实现前置,环绕,异常通知     1. Spring AOP  前置通知 XML配置使用案例     2. Spring AOP   ...

  3. springboot整合redis(注解形式)

    springboot整合redis(注解形式) 准备工作 springboot通常整合redis,采用的是RedisTemplate的形式,除了这种形式以外,还有另外一种形式去整合,即采用spring ...

  4. SpringBoot整合Mybatis多数据源 (AOP+注解)

    SpringBoot整合Mybatis多数据源 (AOP+注解) 1.pom.xml文件(开发用的JDK 10) <?xml version="1.0" encoding=& ...

  5. 一个最简单的通过自定义注解形式实现AOP的例子

    1.首先实现AOP实例的第一步即声明切面类,两种方式(1.基于注解形式@Aspect,2.基于xml配置,一般都通过注解来声明切面类) 2.切入点表达式大致也有两种,一种是直接根据方法的签名来匹配各种 ...

  6. Spring 注解形式AOP

    AOP 面向切面编程,通过预编译的方式,在运行期通过动态代理实现一种技术,AOP可实现业务与切面的逻辑分离,降低耦合度 一.注解形式的AOP Aspect:切面 Joinpoint:连接点,要拦截的方 ...

  7. spring框架aop用注解形式注入Aspect切面无效的问题解决

    由于到最后我的项目还是有个邪门的错没解决,所以先把文章大概内容告知: 1.spring框架aop注解扫描默认是关闭的,得手动开启. 2.关于Con't call commit when autocom ...

  8. SSM框架——以注解形式实现事务管理

    上一篇博文<SSM三大框架整合详细教程>详细说了如何整合Spring.SpringMVC和MyBatis这三大框架.但是没有说到如何配置mybatis的事务管理,在编写业务的过程中,会需要 ...

  9. spring面向切面编程示例(xml配置形式vs@注解形式)

    一.xml配置形式 1.在Spring配置文件中增加面向切面配置当调用com.activemq.service.impl.ConsumerServiceImpl接口实现类的任意方法时执行切面类中的方法 ...

随机推荐

  1. 豆瓣 jsonp 请求数据 并分页

    豆瓣分页 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4 ...

  2. 【转】C语言条件编译及编译预处理阶段

    原文: http://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html 1. 宏定义(宏代换,宏替换,宏: 宏定义是C语言提供的3中预处理功能 ...

  3. swift2.0学习之拓展

    拓展:和oc的拓展方法功能差点儿相同.就是给已经存在的类,结构体.枚举,协议类型添加新的方法 拓展语法: 用extensionkeyword声明: extension SomeType { // ne ...

  4. 极光推送案例-PushExample-Jpush

    ssh - maven - java项目-极光注冊id完毕推送 这是我学习时的步骤: 1:去极光推送平台注冊账号,自己能够去注冊(一般公司会帮助完毕注冊) 地址:https://www.jpush.c ...

  5. NS3网络仿真(2):first.py

    1    安装基本模块 11  安装Python 12  安装PTVS 13  加入对python-279的支持 2    在vs2013下编译NS3 3    编译NetAnim 4    在vs2 ...

  6. 欣喜若狂!今天最终成功把音频导入到iphone了,大半年的努力,靠的毅力和方法

    研究IOS 的助手也有大半年时间了,一直没有实现导入音视频文件的功能,主要是过程太复杂,而且基本上没有资料能够查询.经过不懈的努力,今天最终成功导入了一个mp3 文件到ipod,一切功能正常,期间经历 ...

  7. MTK camera 闪光灯Flashlight驱动调试流程

    MTK camera 闪光灯Flashlight驱动调试流程 分类: MtkDev  |  作者: topicdev 相关  |  发布日期 : 2014-09-26  |  热度 : 153°   ...

  8. 我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录

    我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录 准备安装包: gcc48 glibc--SP4-DVD-x86_64-GM-DVD1.iso tensorflow_ ...

  9. linux 编译安装TRMPdump(libRTMP)

    需要编译libRTMP,首先需要安装配置编译环境.网上能够找到的资料多是在Windows环境编译.这里介绍一下在Linux系统中编译安装libRTMP,一来给后来者一个参考,二来也给自己做一个备忘录. ...

  10. warning: here-document at line 7 delimited by end-of-file (wanted `rui')