最近开始学着做Java服务器端开发,对注解一知半解的。今天刚好发现有一个业务场景可以通过自己实现注解简化代码,所以尝试着做起来。我发现Annotation+AspectJ是一个非常强大的组合,可以做很多事情。
下面这个checkRamPermission
方法是用来做权限检查的。基本上各个入口方法都需要在最开始的地方加上这行代码。看起来很繁琐,也不够酷。所以琢磨用注解的方法来实现。
openApiUtil.checkRamPermission(request, request.getAction(), ResouceType.PRODUCT, String.valueOf(request.getProductId()), true);
checkRamPermission
方法的参数分为好几种。分别如下所示。
- 请求者传入的参数,如request。
- 不同语境下的固定参数。如ResouceType.PRODUCT。
- 不同语境下从request各子类里面提取的属性。如request.getProductId()。
针对上面这些参数定义好注解。请求者传入的参数可以通过反射获取。注解里面只需包含语境相关的信息就行。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RAMAnnotation {
public String resourceType();
public String resourceId() default "";
}
接着定义好AspectJ的pointcut。
@Aspect
public class RAMPointCut {
@Pointcut("@annotation(com.alibaba.cloudmobile.mhub.util.RAMAnnotation)")
public void checkPemission() {}
}
接着就是实现拦截的方法。通过joinPoint获取到方法的信息,包括参数值,这样就可以获取到request对象。因为request子类众多,需要resourceId辅助,以获取具体子类方法,进一步得到resourceId。
@Before(value = "com.alibaba.cloudmobile.mhub.util.RAMPointCut.checkPemission()")
public void ramCheckPemission(JoinPoint joinPoint) {
try {
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
Annotation[] annotations = methodSig.getMethod().getDeclaredAnnotations();
RAMAnnotation annotation = (RAMAnnotation) annotations[0];
Object[] methodArgs = joinPoint.getArgs();
BasePopRequest request = (BasePopRequest) methodArgs[0];
String action = request.getAction();
String resourceId = null;
Method method = null;
if (annotation.resourceId().equals("productId")) {
method = request.getClass().getDeclaredMethod("getProductId");
} else if (annotation.resourceId().equals("appId")) {
method = request.getClass().getDeclaredMethod("getAppId");
}
if (method != null) {
resourceId = String.valueOf(method.invoke(request));
}
openApiUtil.checkRamPermission(request, action, annotation.resourceType(), resourceId, true);
} catch (Throwable e) {
logger.error("RAMAnnotation" + e.getMessage());
throw e;
}
}
使用方式如下。resourceType和resourceId使用枚举类型会很合理一些。注解的属性只支持Java的内置类型,不支持用户自定义的类型。
@RAMAnnotation(resourceType = "product", resourceId = "productId")
public QueryProductInfoResponse queryProductInfo(QueryProductInfoRequest request) throws Throwable
{
}
参考资料。