Spring uses AOP to synchronize the cache for Redis

Source: Internet
Author: User
Tags delete key object object throwable

No more nonsense.

Next idea: using AOP annotations, in the service implementation class add the need to use the Redis method, when each request came over to intercept it, if the query is from Redis get key, if it is update delete key, Prevent dirty data or historical data from appearing. Suggested that AOP does not understand the classmate or spel is not too familiar with the first to see the data back to see, will be more effective.

1. First attach the core annotation class

@Retention (retentionpolicy.runtime) @Target ({Elementtype.method}) Public@InterfaceRedislogservice {    enumcache_operation {FIND,//Query Cache OperationsUPDATE,//need to perform a modify cache operationINSERT;//action required to perform a new cache    }    /**Grouped by storage*/string[] Group (); /**Current cache operation type*/cache_operation cacheoperation ()defaultcache_operation.    FIND; /**the stored key is added by default to the class name followed by the method name*/String key ()default""; /**whether to use the cache*/    BooleanUse ()default true; /**Timeout period*/    intExpire ()default0; enumlog_operation {on,//turn on Log recordsOFF,//Turn off logging    }    /**Current cache operation type*/log_operation logoperation ()defaultlog_operation.    On; /**Action name*/String name ()default""; /**Operating Parameters*/String param ()default""; /**Log parameter operator operation IP, Operation IP Attribution*/String logparam ()default"";

Explain the next part of the parameter

Enum Cache_operation {
Find,//query cache operation
UPDATE,//need to perform an action to modify the cache
INSERT; Action required to perform a new cache
}

The default is find, which changes the annotations on the service if it is update.

2.Service How to use

@RedisLogService (group = {
"Group.news"}, Key = "#record", name = "Website Maintenance-company news Management-paging query company news", param = "#record", Logparam = "#map")

Here I am taking the query as an example, here I only add 5 parameters, the first is the group is the meaning of groups, used as a prefix to identify a module, such as the news module unification is the beginning of the Group.news, the second key can be understood as stored in the Redis key, follow-up will do a detailed answer The third name does not explain, the display is only, the fourth param is the operation parameter; The fifth one is the log, this is not a tube.

3. Paste the specific interception class

@Aspect @order (value= 1) @Component ("Redislogserviceinterceptor") Public classRedislogserviceinterceptor {Private Static FinalLogger Logger = Loggerfactory.getlogger (redislogserviceinterceptor.class); @AutowiredPrivateUserlogrecordservice Userlogrecordservice; @AutowiredPrivateRedistemplate<string, object>redistemplate; /*** * * @Title: Execute * @Description: pointcut business logic *@paramProceedingjoinpoint *@return     */@Around ("@annotation (Redislogservice)")     PublicObject Execute (proceedingjoinpoint proceedingjoinpoint)throwsserviceexception {Object result=NULL; Try{Method Method=GetMethod (Proceedingjoinpoint); //Get Annotation ObjectRedislogservice Redislogservice = method.getannotation (redislogservice.class); //determine whether to use the cache            BooleanUseredis =Redislogservice.use (); if(Useredis) {//using RedisValueoperations<string, object> operations =Redistemplate.opsforvalue (); //Judging the current operation                Switch(Redislogservice.cacheoperation ()) { CaseFind:result=Executedefault (Redislogservice, Operations, Proceedingjoinpoint, method);  Break;  CaseUpdate:result=executeupdate (Redislogservice, Operations, Proceedingjoinpoint);  Break;  CaseInsert:result=Executeinsert (Redislogservice, Operations, Proceedingjoinpoint);  Break; default: Result=proceedingjoinpoint.proceed ();  Break; }            } Else{result=proceedingjoinpoint.proceed (); }        } Catch(serviceexception e) {Throwe; } Catch(Throwable e) {Throw NewServiceexception (NewResult<object> ("500", E.getmessage ()), e); }        returnResult }

/**
*
* @Title: GetMethod
* @Description: Gets the intercepted method object
* @param joinpoint
* @return
*/
Protected Method GetMethod (Joinpoint joinpoint) throws Exception {

Methodsignature methodsignature = (methodsignature) joinpoint.getsignature ();

Method method = Methodsignature.getmethod ();

return method;
}

You can see this annotation through the @around wrapping section here, because @around is able to execute a piece of logic at the same time before and after the intercepted method, for example, I go to redis before querying, and find out that no database is checked, I also need to return to the result set to Redis, So that's a big part of it.

4. Follow the specific implementation method of the query

/*** * @Title: Executedefault * @Description: Execution of default action *@paramRedislogservice *@paramresult *@paramOperations *@paramProceedingjoinpoint *@parammethod *@throwsThrowable*/@SuppressWarnings ("Unchecked")    PrivateObject Executedefault (Redislogservice redislogservice, valueoperations<string, object>operations, Proceedingjoinpoint Proceedingjoinpoint, method)throwsthrowable {Object result=NULL; Object[] args=Proceedingjoinpoint.getargs (); //gets the list of blocked method parameter names (using the Spring Support class library)Localvariabletableparameternamediscoverer U =NewLocalvariabletableparameternamediscoverer (); String[] Paranamearr=U.getparameternames (method); //gets the parameter name of the suffix of the keyString key =Redislogservice.key (); if(Stringutils.isnotblank (key)) {//using Spel for key parsingExpressionParser parser =NewSpelexpressionparser (); //Spel ContextStandardevaluationcontext context =NewStandardevaluationcontext (); //Put the method parameter into the Spel context             for(inti = 0; i < paranamearr.length; i++) {context.setvariable (Paranamearr[i], args[i]); } Object Object=parser.parseexpression (key). GetValue (context); if(NULL!=object) {                if(Objectinstanceofmap<?,? >) {Key= Gzdtlstringutil.transmaptostring ((map<string, object>) object); } Else if(ObjectinstanceofCollection<?>) {Collection<Object> collection = (collection<object>) object; StringBuffer StringBuffer=NewStringBuffer ();  for(Object o:collection) {stringbuffer.append (o.tostring ()); } Key=stringbuffer.tostring (); } Else{Key=object.tostring (); }}} String className=proceedingjoinpoint.gettarget (). GetClass (). GetName (); if(Classname.indexof (".") >= 0) {ClassName= Classname.substring (Classname.lastindexof (".") + 1, Classname.length ()); } String methodName=Method.getname (); String[] group=Redislogservice.group (); if(NULL! = Group && group.length > 0) {            if(Stringutils.isnotblank (key)) {key= Group[0] + ":" + ClassName + ":" + MethodName + ":" +key; } Else{Key= Group[0] + ":" + ClassName + ":" +MethodName; }        } Else {            if(Stringutils.isnotblank (key)) {key= "Group" + ":" + ClassName + ":" + MethodName + ":" +key; } Else{Key= "Group" + ":" + ClassName + ":" +MethodName; }} result=Operations.get (key); //Update the cache if the cache does not have data        if(Result = =NULL) {result=proceedingjoinpoint.proceed (); intexpire =Redislogservice.expire (); //Update Cache            if(Expire > 0) {Operations.set (key, result, expire, timeunit.seconds); } Else{operations.set (key, result); }        }        returnresult; }
View Code

Explain object[] args = Proceedingjoinpoint.getargs (); Here is the parameter taken from the method

The emphasis here is on Proceedingjoinpoint.getargs (); it's conditional.

Public result<pageinfo<webinfobase>> Findpagebyparam (Webinfofindparam record, map<string, String> Map

Above this method I was passed in is the entity Bean, alias must write record, otherwise parsing will not parse the time, map is my log parameters, temporarily without tube.

Then use Spel to parse out the query parameters.

The assembly key is a unique key consisting of the Grop+ class name + method name + incoming parameters.

Finally, from the Redis get this key, found not to let its query completed after the successful return to the AOP interceptor to set, so that the key and value successfully saved to Redis.

Follow up again if it is how to synchronize the update, the beginning said that actually delete this key, because the content has changed after the update.

Spring uses AOP to synchronize the cache for Redis

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.