使用@Aspect更改方法签名

时间:2019-03-21 20:44:34

标签: java spring spring-boot annotations aspect

您可以在Spring中使用方面更改方法的签名吗?

像有效地改变了以下内容:

@GetMapping("/thing")
@User // custom annotation that should authenticate the user
public ResponseEntity getThing() {
    ... // user is successfully authenticated, get the "thing" from the database
}

进入:

@GetMapping("/thing")
public ResponseEntity getThing(@CookieValue("Session-Token") String sessionToken) {
    User user = authenticator.authenticateSessionTokenOrThrow(sessionToken);
    ... // user is successfully authenticated, get the "thing" from the database
}

变量user也可以在方法主体中使用。

如果没有,如何在不重复代码(参数和身份验证器调用)的情况下达到相同的结果?

1 个答案:

答案 0 :(得分:1)

不是为了这个。

是的,他们可以通过编译或运行时编织有效地修改.class文件的字节码,但是不要覆盖方法的签名。

此外,默认的Spring AOP Aspects是用纯Java实现的,因此无法触及字节码层。为此,您需要AspectJ。

在运行/编译时用于自定义字节码的工具为ASMByteBuddy,CGLIB或Javassist。


但是,您可能可以通过Annotation Processor完成此操作,它可以让您修改实际的而不是已经编译的字节码。


  

如果没有,如何在不重复代码的情况下达到相同的结果   (参数和身份验证器调用)无处不在?

可能的解决方案是

  1. HandlerInterceptor,如果用户未通过身份验证,它只会抛出Exception
  2. 标准的Spring AOP建议,如果用户未通过身份验证,则仅引发Exception
  3. Spring Security

1很简单。
2比较耗时
3恕我直言,这似乎是身份验证的最佳选择,但这是最复杂的,可能是


  

HandlerInterceptor可以选择适用于哪些方法?

不幸的是,没有。几个月前,我要求使用Interceptor仅“覆盖”某些方法,并且实现了一个自定义解决方案,该解决方案只是在方法本身上查找指定的注释。

这是我的自定义HandlerInterceptor的摘录,它首先在类型上查找CheckInit批注,然后在方法上查找更具体的自定义。

@Override
public boolean preHandle(
        final HttpServletRequest request,
        final HttpServletResponse response,
        final Object handler
) throws Exception {
    if (handler instanceof HandlerMethod) {
        if (shouldCheckInit((HandlerMethod) handler)) {
            checkInit();
        }
    }

    return true;
}

private static boolean shouldCheckInit(final HandlerMethod handlerMethod) {
    final var typeAnnotation = handlerMethod.getBeanType().getAnnotation(CheckInit.class);
    final var shouldCheckInit = typeAnnotation != null && typeAnnotation.value();

    final var methodAnnotation = handlerMethod.getMethodAnnotation(CheckInit.class);
    return (methodAnnotation == null || methodAnnotation.value()) && shouldCheckInit;
}

private void checkInit() throws Exception {
    if (!manager.isActive()) {
        throw new NotInitializedException();
    }
}
  

“标准Spring AOP建议”似乎很有趣,您是否有链接   为此吗?

Spring AOP documentation-寻找基于Java的配置(我讨厌XML)

  

AspectJ确实触及了字节码,还可以修改签名吗?

您可以使AspectJ修改签名。只需分叉项目并修改其Java代理或编译器即可。

  

AFAIK注释处理器无法修改类,它们只能   创建新的。

问题是,它们不修改.class文件,而是修改源文件,这意味着他们只是对其进行编辑。例如。 Lombok使用注释处理来修改源文件。

但是,是的,修改后的源将写入新文件。