首页 > 解决方案 > 为什么不能使用spring AOP更改响应类型,除了返回对象

问题描述

我正在使用 Spring AOP 来点切我的控制器方法并尝试将通用结构响应返回到前端。定义应如下所示:

public class CommonResponse {

private String status;

private String message;

private Object data;
}

我还有一个点定义如下:

@Aspect
@Component
public class PostMessageInterceptor {


@Pointcut("within(org.moa.controller.*)")
public void postMessageConvert() {}

@Around("postMessageConvert()")
public CommonResponse modifyResult(ProceedingJoinPoint pjp) {
    CommonResponse response = new CommonResponse();
    try {
        Object result = pjp.proceed();
        response.setStatus("success");
        response.setData(result);
    }catch(Throwable t) {
        response.setStatus("failure");
        response.setMessage(t.getMessage());
    }
    return response;
}
}

例如,当控制器返回类型中的方法为 时Map<String,String>modifyResult执行后返回类型已转换为CommonResponsefrom Map<String,String>,则 Spring AOP 将发生异常java.lang.ClassCastException: CommonResponse cannot be cast to java.util.Map

如果我将此方法的返回类型更改为 Object,它将正常工作。

我只是想这是这样设计的吗?否则,有什么方法可以在不将返回类型修改为 Object 的情况下实现此目标。因为感觉很奇怪,所有方法都返回相同类型的 Object。

标签: javaspring-mvcspring-bootaspectjspring-aop

解决方案


您不能更改被包围方法的返回类型。JVM 的机制不允许这样做(请参阅问题的答案)。

您的方法的调用者根据原始方法的接口编译他的代码,但是在执行您的 adivice 之后,该方法返回了不同的类型。那应该如何工作?

一种可能性是使用接口并返回由您的建议创建的不同实现,例如:

interface MyReturnType {
  int getStatus();
  Map<String, String> getData();
}

class MethodReturnType implements MyReturnType {
  int getStatus() { throw NotImplementedException(); } 
  // should never be called; every other method in the interface can be implemented in the exact same way


  Map<String, String> getData() { return data; } // I omit the constructor and field decleration here
}

class AdviceReturnType implements MyReturnType {
  int status;
  Map<String, String> data;

  int getStatus() { return status; } 
  Map<String, String> getData() { return data; }
}


public MyReturnType myAdvicedMethod(...) {
  // ...
  return new MethodReturnType(myCalculatedData);
}

public Object aroundAdvice(ProceedingJoinPoint pjp) {
  MyReturnType retVal = (MyReturnType) pjp.proceed();
  // calculate status and stuff
  return new AdviceReturnType(retVal.getData(), caluclatedStatus, ...);
}

推荐阅读