JavaとKotlinのカスタムコメントは、キャッシュマネージャの代わりに操作可能なEL注釈を実現します。


今日実現したのはキャッシュマネージャの代替であり、私自身の小さな試みでもあります。足りないところがあったら皆さんに提出してください。思想の大部分はRedisのキャッシュマネージャの考え方によって来ました。
前言:
spring bootバージョン2.1.6.RELEASEはredisを導入します。
  		
            org.springframework.boot
            spring-boot-starter-data-redis
        
AOPの導入
        
            org.springframework.boot
            spring-boot-starter-aop
        
FastJsonを導入する
		
            com.alibaba
            fastjson
            1.2.61
        
注釈上のパラメータは意味keyで代表されるキャッシュプレフィックスの例user:info:keysはプレフィックスの後につづり合わせたパラメータの値を表します。例keys="phone"は、転送方法のphoneのパラメータは1234です。キャッシュに書き込むkeyは、user:info:1234です。これはEL表达式を書いて、オブジェクトパラメータのある値を解析することができます。例はUkeysr=Ukerです。「(i)user.phone」では、解析後はuser:info:これはパラメータを書かないと、この方法のすべてのパラメータを並べ替えてkeyを生成します。3つの注釈があり、3つのAOPカットの実現カテゴリがあり、EL式解析類RedisSetString書き込みと更新RedisGetStringは単にRedisDelStringを取得して削除します。
今日はまずkotlinに来ます。
Ktlin
まず3つの注釈を書きます。RedisSetString、RedisGetString、RedisDelString
注:Redis Set Stringコードは以下の通りです。
@Target(AnnotationTarget.FUNCTION)			//        
@Retention(AnnotationRetention.RUNTIME)		//     
@MustBeDocumented
annotation class RedisSetString(val key: String = "", val keys: String = "", val expire: Long = 0L, val timeUnit: TimeUnit = TimeUnit.SECONDS)
    :
key --     
keys --                   key,
expire --       ,   0L
timeUnit --          ,    

注:RedisGet Stringコードは以下の通りです。
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RedisGetString(val key: String = "", val keys: String = "")
key --     
keys --                   key,

注:RedisDel Stringコードは以下の通りです。
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class RedisDelString(val key: String = "", val keys: String = "")
上に3つの注解のコードがあります。次はKeysが取得して解析するクラスです。EL式をサポートして、AsppectExpressionクラスを作成します。
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.bedding.core.exception.NotFoundException
import org.aspectj.lang.ProceedingJoinPoint
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.core.DefaultParameterNameDiscoverer
import org.springframework.expression.EvaluationContext
import org.springframework.expression.Expression
import org.springframework.expression.spel.standard.SpelExpressionParser
import org.springframework.expression.spel.support.StandardEvaluationContext
import java.lang.Exception
import java.lang.StringBuilder
import java.lang.reflect.Method

object AspectExpression {

    /**
     *   SpEL     .
     */
    private val parser = SpelExpressionParser()
    /**
     *             .
     */
    private val nameDiscoverer = DefaultParameterNameDiscoverer()

    private val logger: Logger = LoggerFactory.getLogger(AspectExpression::class.java)

    fun getKey(keys: String, method: Method, joinPoint: ProceedingJoinPoint): String {
        //   spring DefaultParameterNameDiscoverer         
        val paramNames = nameDiscoverer.getParameterNames(method)
        //   joinPoint          
        val args = joinPoint.args
        return if (!paramNames.isNullOrEmpty()) {
            //     keys ,            key,         
            if (keys == "") {
                val value = StringBuffer()
                args.forEach {
                    val str = getStr(it)
                    if (str.first().toString() == ":") {
                        value.append(str)
                    } else {
                        value.append(":").append(str)
                    }
                }
                value.toString()
            }
            //   keys
            else {
                // keys    #     el   ,
                if (!keys.contains("#")) {
                    getStr(args[paramNames.toList().indexOf(keys)])
                }
                //  #  ,    EL   
                else {
                    //      Spring     
                    val expression: Expression = parser.parseExpression(keys)
                    // spring         
                    val context: EvaluationContext = StandardEvaluationContext()
                    //       
                    for (i in args.indices) {
                        context.setVariable(paramNames[i], args[i])
                    }
                    expression.getValue(context).toString()
                }
            }
        } else {
            throw NotFoundException("         ")
        }
    }

    //         
    private fun getStr(any: Any): String {
        return try {
            val data = JSON.parseObject(JSON.toJSONString(any), JSONObject()::class.java)
            //         
            val keySet = data.keys.sorted()
            val value = StringBuffer()
            keySet.forEach {
                if (data[it] != null) {
                    value.append(":").append(data[it])
                }
            }
            value.toString()
        } catch (e: Exception) {
            any.toString()
        }
    }
}
keysを入力すれば解析後の値に戻り、RedisSet Stringを作成するAOPカット類RedisSet StrigAsppectは、SteringRedisTemplate類RedisSetStringを導入する必要があります。
import com.alibaba.fastjson.JSON
import com.bedding.web.core.annotations.RedisSetString
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.*
import org.aspectj.lang.reflect.MethodSignature
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Component*

@Aspect
@Component
class RedisSetStringAspect(private val redisTemplate: StringRedisTemplate) {

    private val logger: Logger = LoggerFactory.getLogger(RedisSetStringAspect::class.java)

    @Pointcut("@annotation(com.bedding.web.core.annotations.RedisSetString)")
    fun pointcutRedisSetString() {
    }
	
	//    
	//          @RedisSetString      
    @Around("pointcutRedisSetString()")
    fun redisSetStringBefore(joinPoint: ProceedingJoinPoint): Any {
        val sign: MethodSignature = joinPoint.signature as MethodSignature
        val method = sign.method
        //        
        val annotation = method.getAnnotation(RedisSetString::class.java)
        //keys    
        val parameter = AspectExpression.getKey(annotation.keys, method, joinPoint)
        //          ":",      
        val key = if (parameter.first().toString() == ":"){
            "${annotation.key}${parameter}"
        }else{
            "${annotation.key}:${parameter}"
        }
        //               
        val result = joinPoint.proceed()
        //       FastJson
        if (annotation.expire != 0L) {
        //           0L      
            redisTemplate.opsForValue().set(key, JSON.toJSONString(result))
        } else {
        //              
            redisTemplate.opsForValue().set(key, JSON.toJSONString(result), annotation.expire, annotation.timeUnit)
        }
        return result
    }

}
その後、RedisGetStringを作成するAOPカット類RedisGetStrigAsppectは、StrigRedisTemplate類RedisGetStringのコードを以下の通り導入する必要があります。
import com.alibaba.fastjson.JSON
import com.bedding.web.core.annotations.RedisGetString
import org.aspectj.lang.ProceedingJoinPoint
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.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Component


@Aspect
@Component
class RedisGetStringAspect(private val redisTemplate: StringRedisTemplate) {

    private val logger: Logger = LoggerFactory.getLogger(RedisGetStringAspect::class.java)


    @Pointcut("@annotation(com.bedding.web.core.annotations.RedisGetString)")
    fun pointcutRedisGetString() {
    }
    
 	//          @RedisGetString      
    @Around(value = "pointcutRedisGetString()")
    fun redisGetStringBefore(joinPoint: ProceedingJoinPoint): Any {
        val sign: MethodSignature = joinPoint.signature as MethodSignature
        val method = sign.method
        //        
        val annotation = method.getAnnotation(RedisGetString::class.java)
        val parameter = AspectExpression.getKey(annotation.keys, method, joinPoint)
        val key = if (parameter.first().toString() == ":"){
            "${annotation.key}${parameter}"
        }else{
            "${annotation.key}:${parameter}"
        }
        //          ,      
        return if (redisTemplate.hasKey(key)) {
        	//  FastJson        ,                     
            JSON.parseObject(redisTemplate.opsForValue().get(key), method.returnType)
        } else {
        	//         ,    
            joinPoint.proceed()
        }
    }
}
その後、RedisDelStringを作成するAOPカット類RedisDelStringAspectは、SteringRedisTemplate類RedisDelStringのコードを以下の通り導入する必要があります。
import com.bedding.core.exception.NotFoundException
import com.bedding.web.core.annotations.RedisDelString
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.*
import org.aspectj.lang.reflect.MethodSignature
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.stereotype.Component


@Aspect
@Component
class RedisDelStringAspect(private val redisTemplate: StringRedisTemplate) {

    private val logger: Logger = LoggerFactory.getLogger(RedisDelStringAspect::class.java)

    @Pointcut("@annotation(com.bedding.web.core.annotations.RedisDelString)")
    fun pointcutRedisDelString() {
    }

    //          @RedisDelString      
    @Around("pointcutRedisDelString()")
    fun redisDelStringBefore(joinPoint: ProceedingJoinPoint): Any {
        val sign: MethodSignature = joinPoint.signature as MethodSignature
        val method = sign.method
        //        
        val annotation = method.getAnnotation(RedisDelString::class.java)
        val parameter = AspectExpression.getKey(annotation.keys, method, joinPoint)
        val key = if (parameter.first().toString() == ":"){
            "${annotation.key}${parameter}"
        }else{
            "${annotation.key}:${parameter}"
        }
        //          
        return if (redisTemplate.hasKey(key)) {
        	//      
            redisTemplate.delete(key)
        } else {
        	//          ,              
            throw NotFoundException("       ")
        }
    }

}
以上はKotlinのカスタムコメントです。Redisキャッシュマネージャの代わりに、これはまだ完璧ではないです。もし皆さんがいい考えを持ってくれたら、私に提供してくれます。私は改善できます。次はJAVAの実現方式です。注釈とクラス名は一致します。
JAVA
同じく3つの注釈RedisSetString、RedisGetString、RedisDelStringコードを書きます。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisSetString {
    public String key() default "";

    public String keys() default "";

    public long expire() default 0L;

    public TimeUnit timeUnit() default TimeUnit.SECONDS;



}

    :
key --     
keys --                   key,
expire --       ,   0L
timeUnit --          ,    

注:RedisGet Stringコードは以下の通りです。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisGetString {
    public String key() default "";

    public String keys() default "";
}

key --     
keys --                   key,

注:RedisDel Stringコードは以下の通りです。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisDelString {
    public String key() default "";

    public String keys() default "";

}
上に3つの注解のコードがあります。次はKeysが取得して解析するクラスです。EL式をサポートして、AsppectExpressionクラスを作成します。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.springcloud.common.core.exception.NotFoundException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class AspectExpression {

    private Logger logger = LoggerFactory.getLogger(AspectExpression.class);

    /**
     *   SpEL     .
     */
    ;
    private static SpelExpressionParser parser = new SpelExpressionParser();
    /**
     *             .
     */
    private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

    public static String getKey(String keys, Method method, ProceedingJoinPoint joinPoint) {
        //   spring DefaultParameterNameDiscoverer         
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        //   joinPoint          
        Object[] args = joinPoint.getArgs();
        //     keys ,            key,         
        if (paramNames != null) {
            if ("".equals(keys)) {
                StringBuffer value = new StringBuffer();
                Arrays.asList(args).forEach(it -> {
                    String str = getStr(it);
                    if (str.subSequence(0, 1) == ":") {
                        value.append(str);
                    } else {
                        value.append(":").append(str);
                    }
                });
                return value.toString();
            }
            //   keys
            else {
                // keys    #     el   ,
                if (!keys.contains("#")) {
                    return getStr(args[Arrays.asList(paramNames).indexOf(keys)]);
                }
                //  #  ,    EL   
                else {
                    //      Spring     
                    Expression expression = parser.parseExpression(keys);
                    // spring         
                    EvaluationContext context =new StandardEvaluationContext();
                    //       
                    for (int i = 0; i < args.length; i++) {
                        context.setVariable(paramNames[i], args[i]);
                    }
                    return Objects.requireNonNull(expression.getValue(context)).toString();
                }
            }
        } else {
            throw new NotFoundException("         ");
        }

    }

    //         
    private static String getStr(Object any) {
        try {
            JSONObject data = JSON.parseObject(JSON.toJSONString(any), JSONObject.class);
            //         
            List keySet = data.keySet().stream().sorted().collect(Collectors.toList());
            StringBuffer value = new StringBuffer();
            keySet.forEach(it -> {
                if (data.get(it) != null) {
                    value.append(":").append(data.get(it));
                }
            });
            return value.toString();
        } catch (Exception e) {
            return any.toString();
        }
    }
}
keysを入力すれば解析後の値に戻り、RedisSet Stringを作成するAOPカット類RedisSet StrigAsppectは、SteringRedisTemplate類RedisSetStringを導入する必要があります。
import com.alibaba.fastjson.JSON;
import com.springcloud.userserver.core.annotations.RedisSetString;
import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisSetStringAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;


    @Pointcut("@annotation(com.springcloud.userserver.core.annotations.RedisSetString)")
    public void pointcutRedisSetString() {
    }

    //          @RedisSetString      
    @Around("pointcutRedisSetString()")
    public Object redisSetStringBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        //        
        RedisSetString annotation = method.getAnnotation(RedisSetString.class);
        String parameter = AspectExpression.getKey(annotation.keys(), method, joinPoint);
        String key;
        if (parameter.subSequence(0, 1) == ":") {
            key = annotation.key() + parameter;
        } else {
            key = annotation.key() + ":" + parameter;
        }
        Object result = joinPoint.proceed();
        if (annotation.expire() != 0L) {
            redisTemplate.opsForValue().set(key, JSON.toJSONString(result));
        } else {
            redisTemplate.opsForValue().set(key, JSON.toJSONString(result), annotation.expire(), annotation.timeUnit());
        }
        return result;
    }

}
その後、RedisGetStringを作成するAOPカット類RedisGetStrigAsppectは、StrigRedisTemplate類RedisGetStringのコードを以下の通り導入する必要があります。
import com.alibaba.fastjson.JSON;
import com.springcloud.userserver.core.annotations.RedisGetString;
import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisGetStringAspect {

    @Autowired
    public StringRedisTemplate redisTemplate;


    @Pointcut("@annotation(com.springcloud.userserver.core.annotations.RedisGetString)")
    public void pointcutRedisGetString() {
    }

    @Around(value = "pointcutRedisGetString()") //          @RedisSetString      
    public Object redisGetStringBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        //        
        RedisGetString annotation = method.getAnnotation(RedisGetString.class);
        String parameter = AspectExpression.getKey(annotation.keys(), method, joinPoint);
        String key;
        if (parameter.subSequence(0, 1) == ":") {
            key = annotation.key() + parameter;
        } else {
            key = annotation.key() + ":" + parameter;
        }
        Boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey != null && hasKey) {
            return JSON.parseObject(redisTemplate.opsForValue().get(key), method.getReturnType());
        } else {
            return joinPoint.proceed();
        }
    }
}
その後、RedisDelStringを作成するAOPカット類RedisDelStringAspectは、SteringRedisTemplate類RedisDelStringのコードを以下の通り導入する必要があります。
import com.springcloud.common.core.exception.NotFoundException;
import com.springcloud.userserver.core.annotations.RedisDelString;
import org.aspectj.lang.ProceedingJoinPoint;
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.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisDelStringAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Logger logger = LoggerFactory.getLogger(RedisDelStringAspect.class);

    @Pointcut("@annotation(com.springcloud.userserver.core.annotations.RedisDelString)")
    public void pointcutRedisDelString() {
    }

    //          @RedisDelString      
    @Around("pointcutRedisDelString()")
    public Object redisDelStringBefore(ProceedingJoinPoint joinPoint) {
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        //        
        RedisDelString annotation = method.getAnnotation(RedisDelString.class);
        String parameter = AspectExpression.getKey(annotation.keys(), method, joinPoint);
        String key;
        if (parameter.subSequence(0, 1) == ":") {
            key = annotation.key() + parameter;
        } else {
            key = annotation.key() + ":" + parameter;
        }
        Boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey != null && hasKey) {
            return redisTemplate.delete(key);
        } else {
            throw new NotFoundException("       ");
        }
    }
}
関連コードはアップロードされました。リンクをダウンロードします。https://download.csdn.net/download/qq_40466900/12737503 必要なポイント:0
以上はJAVAの自定の注釈とAOPの切断面がRedisの書き込みを実現して、更新して調べて削除します。
もっと良い実現方法があれば、一緒におしゃべりして、もっと完璧になります。