举例,自定义redis模糊删除注解
import java.lang.annota形容热的成语tion.elementtype;import java.lang.annotation.retention;import java.lang.annotation.retentionpolicy;import java.lang.annotation.target; @target(elementtype.method)@retention(retentionpolicy.runtime)public @interface cacheevictf委屈的近义词是什么uzzy { /** * redis key集合,模糊删除 * @return */ 敬谢 string[] key() default ""; }
import org.apache.commons.lang3.stringutils;import org.aspectj.lang.proceedingjoinpoint;import org.aspectj.lang.annotation.afterthrowing;import org.aspectj.lang.annotation.around;import org.aspectj.lang.annotation.aspect;import org.aspectj.lang.annotation.pointcut;import org.aspectj.lang.reflect.methodsignature;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.beans.factory.annotation.autowired;import org.springframework.core.localvariabletableparameternamediscoverer;import org.springframework.core.annotation.order;import org.springframework.expression.expressionparr;import org.springframework.expression.spel.standard.spelexpressionparr;import org.springframework.expression.spel.support.standardevaluationcontext;import org.springframework.stereotype.component; import java.lang.reflect.method;import java.util.t;@aspect@order(1)@componentpublic class cachecleanfuzzyaspect { logger logger = loggerfactory.getlogger(this.getclass()); @autowired private redisutil redis; //指定要执行aop的方法 @pointcut(value = "@annotation(cacheevictfuzzy)") public void pointcut(cacheevictfuzzy cacheevictfuzzy){} // 设置切面为加有 @rediscacheable注解的方法 @around("@annotation(cacheevictfuzzy)") public object around(proceedingjoinpoint proceedingjoinpoint, cacheevictfuzzy cacheevictfuzzy){ return doredis(proceedingjoinpoint, cacheevictfuzzy); } @afterthrowing(pointcut = "@annotation(cacheevictfuzzy)", throwing = "error") public void afterthrowing (throwable error, cacheevictfuzzy cacheevictfuzzy){ logger.error(error.getmessage()); } /** * 删除缓存 * @param proceedingjoinpoint * @param cacheevictfuzzy * @return */ private object doredis (proceedingjoinpoint proceedingjoinpoint, cacheevictfuzzy cacheevictfuzzy){ object result = null; //得到被切面修饰的方法的参数列表 object[] args = proceedingjoinpoint.getargs(); // 得到被代理的方法 method method = ((methodsignature) proceedingjoinpoint.getsignature()).getmethod(); string[] keys = cacheevictfuzzy.key(); t<string> keyt = null; string realkey = ""; for (int i = 0; i < keys.length; i++) { if (stringutils.isblank(keys[i])){ continue; } realkey = parkey(keys[i], method, args); keyt = redis.keys("*"+realkey+"*"); if (null != keyt && keyt.size()>0){ redis.delkeys(keyt); logger.debug("拦截到方法:" + proceedingjoinpoint.getsignature().getname() + "方法"); logger.debug("删除的数据key为:"+keyt.tostring()); } } try { result = proceedingjoinpoint.proceed(); } catch (throwable throwable) { throwable.printstacktrace(); }finally { return result; } } /** * 获取缓存的key * key 定义在注解上,支持spel表达式 * @return */ private string parkey(string key, method method, object [] args){ if(stringutils.impty(key)) return null; //获取被拦截方法参数名列表(使用spring支持类库) localvariabletableparameternamediscoverer u = new localvariabletableparameternamediscoverer(); string[] paranamearr = u.getparameternames(method); //使用spel进行key的解析 expressionparr parr = new spelexpressionparr(); //spel上下文 三星s8什么时候上市 standardevaluationcontext context = new standardevaluationcontext(); //把方法参数放入spel上下文中 for(int i=0;i<paranamearr.length;i++){ context.tvariable(paranamearr[i], args[i]); } return parr.parexpression(key).getvalue(context,string.class); }}
完事啦!
大家可以注意到关键方法就是parkey
/** * 获取缓存的key * key 定义在注解上,支持spel表达式 * @return */ private string parkey(string key, method method, object [] args){ if(stringutils.impty(key)) return null; //获取被拦截方法参数名列表(使用spring支持类库) localvariabletableparameternamediscoverer u = new localvariabletableparameternamediscoverer(); string[] paranamearr = u.ge祝老师端午节的祝福语tparameternames(method); //使用spel进行key的解析 expressionparr parr = new spelexpressionparr(); //spel上下文 standardevaluationcontext context = new standardevaluationcontext(); //把方法参数放入spel上下文中 for(int i=0;i<paranamearr.length;i++){ context.tvariable(paranamearr[i], args[i]); } return parr.parexpression(key).getvalue(context,string.class); }
在我们的实际开发中可能存在这么一种情况,当方法参数中的某些条件成立的时候,需要执行一些逻辑处理,比如输出日志。而这些代码可能都是差不多的,那么这个时候就可以结合自定义注解加上切面加上spel表达式进行处理。就比如在spring中我们可以使用@cacheable(key=”#xx”)实现缓存,这个#xx就是一个spel表达式。
需求:我们需要将rvice层方法中方法的某个参数的值大于0.5的方法,输出方法执行日志。(需要了解一些spel表达式的语法)
实现步骤:
1、自定义一个注解log
2、自定义一个切面,拦截所有方法上存在@log注解修饰的方法
3、写一个rvice层方法,方法上标注@log注解
难点:
在切面中需要拿到具体执行方法的方法名,可以使用spring提供的localvariabletableparameternamediscoverer来获取到
注意:注解中的spel的值是必须的,且spel表达式返回的结果应该是一个布尔值
/** * 记录日志信息,当spel表但是中的值为true时,输出日志信息 * * @描述 * @作者 huan * @时间 2017年10月2日 - 上午10:25:39 */@target({ elementtype.method })@retention(retentionpolicy.runtime)public @interface log {string spel();string desc() default "描述";}
注意一下解析spel表达式中context的设值即可
/** * 日志切面,当条件满足时输出日志. * * @描述 * @作者 huan * @时间 2017年10月2日 - 上午10:32:16 */@component@aspectpublic class logaspect {expressionparr parr = new spelexpressionparr();localvariabletableparameternamediscoverer discoverer = new localvariabletableparameternamediscoverer();@around("@annotation(log)")public object invoked(proceedingjoinpoint pjp, log log) throws throwable {object[] args = pjp.getargs();method method = ((methodsignature) pjp.getsignature()).getmethod();string spel = log.spel();string[] params = discoverer.getparameternames(method);evaluationcontext context = new standardevaluationcontext();for (int len = 0; len < params.length; len++) {context.tvariable(params[len], args[len]);}expression expression = parr.parexpression(spel);if (expression.getvalue(context, boolean.class)) {system.out.println(log.desc() + ",在" + new simpledateformat("yyyy-mm-dd hh:mm:ss").format(new date()) + "执行方法," + pjp.gettarget().getclass() + "." + method.getname() + "(" + convertargs(args) + ")");}return pjp.proceed();}private string convertargs(object[] args) {stringbuilder builder = new stringbuilder();for (object arg : args) {if (null == arg) {builder.append("null");} el {builder.append(arg.tostring());}builder.append(',');}builder.tcharat(builder.length() - 1, ' ');return builder.tostring();}}
<parent><groupid>org.springframework.boot</groupid><artifactid>spring-boot-starter-parent</artifactid><version>1.5.2.relea</version><relativepath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceencoding>utf-8</project.build.sourceencoding><project.reporting.outputencoding>utf-8</project.reporting.outputencoding><java.version>1.8</java.version></properties><dependencies><dependency><groupid>org.springframework.boot</groupid><artifactid>spring-boot-starter-aop</artifactid></dependency><dependency><groupid>org.springframework.boot</groupid><artifactid>spring-boot-starter-test</artifactid><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupid>org.springframework.boot</groupid><artifactid>spring-boot-maven-plugin</artifactid></plugin></plugins></build>
1、当我们想在自己写的spel表达式中调用spring bean 管理的方法时,如何写。spel表达式支持使用 @来引用bean,但是此时需要注入beanfactory
以上为个人经验,希望能给大家一个参考,也希望大家多多支持www.887551.com。
本文发布于:2023-04-05 01:26:05,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/1ba4d5c4e59868fa2fdc9106bfb8f52f.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:使用Springboot自定义注解,支持SPEL表达式.doc
本文 PDF 下载地址:使用Springboot自定义注解,支持SPEL表达式.pdf
留言与评论(共有 0 条评论) |