java - 使用@Aspect更改方法签名

标签 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 变量也可以在方法主体中使用。

如果不是,如何在不到处重复代码(参数和 validator 调用)的情况下获得相同的结果?

最佳答案

方面并不是为此目的。

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

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

用于在运行/编译时自定义字节码的工具有 ASM , ByteBuddy 、CGLIB 或 Javassist。

<小时/>

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

<小时/>

If not, how can I achieve the same result without repeating the code (parameter and authenticator call) everywhere?

可能的解决方案是

  1. HandlerInterceptor ,如果用户未经过身份验证,它只会抛出 Exception
  2. 标准 Spring AOP 建议,如果用户未经过身份验证,它只会抛出 Exception
  3. Spring 安全

1 非常简单。
2 比较耗时
3 恕我直言,似乎是身份验证的最佳匹配,但它可能是最复杂的

<小时/>

The HandlerInterceptor can choose which methods it applies to?

不幸的是,不。几个月前,我需要使用拦截器仅“覆盖”某些方法,并且我实现了一个自定义解决方案,该解决方案仅查找方法本身指定的注释。

这是我的自定义 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();
    }
}

The "Standard Spring AOP advice" seems interesting, do you have a link for that?

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

AspectJ really touches the bytecode and can modify signatures as well?

您可以让 AspectJ 修改签名。只需 fork 该项目并修改其 Java 代理或编译器即可。

AFAIK Annotation Processors cannot modify classes, they can only create new ones.

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

但是,修改后的源代码会写入新文件。

关于java - 使用@Aspect更改方法签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55288966/

相关文章:

java - Spring手动创建组件并注册为单例

java - 如何使用 Rest 和 Spring 安全性通过 ldap 登录 Angular?

spring-boot - 如何使用 env 特定配置创建 Spring Cloud Config Client?

java - 文本编辑器分隔符行号重叠和长行标记

java - ResourceController 上的 NumberFormatException 无法从字符串转换为整数

java - 是否有真实世界的 Spring 和 Hibernate 示例的来源?

Java Spring - 拦截 REST 客户端的执行 (Hystrix Feign)

java - @LastModifiedDate 导致数据库中的额外更新

java - Aspectj:从 HttpServletRresponse 获取响应正文(HTML 文本)

java - 是否可以为接口(interface)类型创建对象