Java Annotation+AspectJ是绝配啊

最近开始学着做Java服务器端开发,对注解一知半解的。今天刚好发现有一个业务场景可以通过自己实现注解简化代码,所以尝试着做起来。我发现Annotation+AspectJ是一个非常强大的组合,可以做很多事情。

下面这个checkRamPermission方法是用来做权限检查的。基本上各个入口方法都需要在最开始的地方加上这行代码。看起来很繁琐,也不够酷。所以琢磨用注解的方法来实现。

openApiUtil.checkRamPermission(request, request.getAction(), ResouceType.PRODUCT, String.valueOf(request.getProductId()), true);

checkRamPermission方法的参数分为好几种。分别如下所示。

  1. 请求者传入的参数,如request。
  2. 不同语境下的固定参数。如ResouceType.PRODUCT。
  3. 不同语境下从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
{
}

参考资料。

  1. 十分钟全面理解Spring AOP
  2. 基于 Annotation 拦截的 Spring AOP 权限验证方法

你可能感兴趣的:(Java Annotation+AspectJ是绝配啊)