JavaとKotlinのカスタムコメントは、キャッシュマネージャの代わりに操作可能なEL注釈を実現します。
今日実現したのはキャッシュマネージャの代替であり、私自身の小さな試みでもあります。足りないところがあったら皆さんに提出してください。思想の大部分はRedisのキャッシュマネージャの考え方によって来ました。
前言:
spring bootバージョン2.1.6.RELEASEはredisを導入します。
今日はまずkotlinに来ます。
Ktlin
まず3つの注釈を書きます。RedisSetString、RedisGetString、RedisDelString
注:Redis Set Stringコードは以下の通りです。
JAVA
同じく3つの注釈RedisSetString、RedisGetString、RedisDelStringコードを書きます。
以上はJAVAの自定の注釈とAOPの切断面が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の書き込みを実現して、更新して調べて削除します。
もっと良い実現方法があれば、一緒におしゃべりして、もっと完璧になります。