下面的代码我想实现的功能是凡是加了@CacheLock 的注解都要进行上锁
package run.halo.app.cache.lock;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* Cache lock annotation.
*
* @author johnniang
* @date 3/28/19
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface CacheLock {
/**
* Cache prefix, default is ""
*
* @return cache prefix
*/
@AliasFor("value")
String prefix() default "";
/**
* Alias of prefix, default is ""
*
* @return alias of prefix
*/
@AliasFor("prefix")
String value() default "";
/**
* Expired time, default is 5.
*
* @return expired time
*/
long expired() default 5;
/**
* Time unit, default is TimeUnit.SECONDS.
*
* @return time unit
*/
TimeUnit timeUnit() default TimeUnit.SECONDS;
/**
* 分隔符, default is ':'
*
* @return delimiter
*/
String delimiter() default ":";
/**
* Whether delete cache after method invocation.
*
* @return true if delete cache after method invocation; false otherwise
*/
boolean autoDelete() default true;
/**
* Whether trace the request info.
*
* @return true if trace the request info; false otherwise
*/
boolean traceRequest() default false;
}
利用AOP 的 Around 判断是否加了 注解 进行拦截
package run.halo.app.cache.lock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import run.halo.app.cache.StringCacheStore;
import run.halo.app.exception.FrequentAccessException;
import run.halo.app.exception.ServiceException;
import run.halo.app.utils.ServletUtils;
import java.lang.annotation.Annotation;
/**
* Interceptor for cache lock annotation.
*
* @author johnniang
* @date 3/28/19
*/
@Slf4j
@Aspect
@Configuration
public class CacheLockInterceptor {
private final static String CACHE_LOCK_PREFOX = "cache_lock_";
private final static String CACHE_LOCK_VALUE = "locked";
private final StringCacheStore cacheStore;
public CacheLockInterceptor(StringCacheStore cacheStore) {
this.cacheStore = cacheStore;
}
@Around("@annotation(run.halo.app.cache.lock.CacheLock)")
public Object interceptCacheLock(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取签名持有注解的方法的签名 methodSignature: AuthToken run.halo.app.controller.admin.api.AdminController.auth(LoginParam)
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
log.debug("Starting locking: [{}]", methodSignature.toString());
// Get cache lock
//methodSignature.getMethod(): public run.halo.app.security.token.AuthToken run.halo.app.controller.admin.api.AdminController.auth(run.halo.app.model.params.LoginParam)
//cacheLock : @run.halo.app.cache.lock.CacheLock(expired=5, traceRequest=false, prefix=, delimiter=:, autoDelete=false, value=, timeUnit=SECONDS)
CacheLock cacheLock = methodSignature.getMethod().getAnnotation(CacheLock.class);
// Build cache lock key
String cacheLockKey = buildCacheLockKey(cacheLock, joinPoint);
log.debug("Built lock key: [{}]", cacheLockKey);
try {
// Get from cache
Boolean cacheResult = cacheStore.putIfAbsent(cacheLockKey, CACHE_LOCK_VALUE, cacheLock.expired(), cacheLock.timeUnit());
if (cacheResult == null) {
throw new ServiceException("Unknown reason of cache " + cacheLockKey).setErrorData(cacheLockKey);
}
if (!cacheResult) {
throw new FrequentAccessException("访问过于频繁,请稍后再试!").setErrorData(cacheLockKey);
}
// Proceed the method
return joinPoint.proceed();
} finally {
// Delete the cache
if (cacheLock.autoDelete()) {
cacheStore.delete(cacheLockKey);
log.debug("Deleted the cache lock: [{}]", cacheLock);
}
}
}
/**
*
* @param cacheLock @run.halo.app.cache.lock.CacheLock(expired=5, traceRequest=false, prefix=, delimiter=:, autoDelete=false, value=, timeUnit=SECONDS)
* @param joinPoint
* @return
*/
private String buildCacheLockKey(@NonNull CacheLock cacheLock, @NonNull ProceedingJoinPoint joinPoint) {
Assert.notNull(cacheLock, "Cache lock must not be null");
Assert.notNull(joinPoint, "Proceeding join point must not be null");
// Get the method methodSignature: AuthToken run.halo.app.controller.admin.api.AdminController.auth(LoginParam)
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
// Build the cache lock key
//cache_lock_
StringBuilder cacheKeyBuilder = new StringBuilder(CACHE_LOCK_PREFOX);
String delimiter = cacheLock.delimiter();
if (StringUtils.isNotBlank(cacheLock.prefix())) {
cacheKeyBuilder.append(cacheLock.prefix());
} else {
cacheKeyBuilder.append(methodSignature.getMethod().toString());
}
// Handle cache lock key building
Annotation[][] parameterAnnotations = methodSignature.getMethod().getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {
log.debug("Parameter annotation[{}] = {}", i, parameterAnnotations[i]);
for (int j = 0; j < parameterAnnotations[i].length; j++) {
Annotation annotation = parameterAnnotations[i][j];
log.debug("Parameter annotation[{}][{}]: {}", i, j, annotation);
if (annotation instanceof CacheParam) {
// Get current argument
Object arg = joinPoint.getArgs()[i];
log.debug("Cache param args: [{}]", arg);
// Append to the cache key
cacheKeyBuilder.append(delimiter).append(arg.toString());
}
}
}
if (cacheLock.traceRequest()) {
// Append http request info
cacheKeyBuilder.append(delimiter).append(ServletUtils.getRequestIp());
}
return cacheKeyBuilder.toString();
}
}