重构方面的异常?

Refactoring exceptions to aspect?

我们有一个用 Spring MVC 开发的大型代码库。以下代码在各处重复。

 public @ResponseBody BaseResponse<String> getSomething() {
    BaseResponse<String> response = new BaseResponse<String>();
    try {
        //something
    } catch (Exception e) {
        BaseError be = ExceptionHandler.errorResponse(e);
        response.setError(be);
    }
    return response;
}

我很好奇这是否可以使用方面进行重构或简化?

ie: ExceptionHandler 可以在方面内调用,但是如何设置响应错误?

谢谢。

我用普通 Java + 原生 AspectJ 重新创建了你的情况,因为我不是 Spring 用户。但是在 Spring AOP 中切面和它的切入点应该是一样的,只是切面也需要是 @Component.

几个假人类:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResponseBody {}
package de.scrum_master.app;

public class BaseError {
    private Exception e;

    public BaseError(Exception e) {
        this.e= e;
    }

    public String getMessage() {
        return e.getMessage();
    }
}
package de.scrum_master.app;

public class ExceptionHandler {
    public static BaseError errorResponse(Exception e) {
        return new BaseError(e);
    }
}
package de.scrum_master.app;

public class BaseResponse<T> {
    private String body;
    private String error = "OK";

    public void setBody(String body) {
        this.body = body;
    }

    public void setError(BaseError be) {
        error = be.getMessage();
    }

    @Override
    public String toString() {
        return "BaseResponse [body=" + body + ", error=" + error + "]";
    }
}

驱动申请:

有两个目标方法返回 BaseResponse<String>,基本上与您的示例方法相同,随机抛出异常,但异常处理被剥离。我想这就是你想要实现的目标。

还有一种方法不被切面作为目标(作为负测试用例)。

package de.scrum_master.app;

import java.util.Random;

public class Application {
    private static final Random RANDOM = new Random();

    public static void main(String[] args) {
        Application application = new Application();
        for (int i = 0; i < 5; i++) {
            System.out.println(application.doSomething());
            System.out.println(application.getSomething());
            System.out.println(application.getSomethingElse());
        }
    }

    public String doSomething() {
        return "Doing something";
    }

    public @ResponseBody BaseResponse<String> getSomething() {
        BaseResponse<String> response = new BaseResponse<String>();
        if (RANDOM.nextBoolean())
            throw new RuntimeException("cannot get something");
        response.setBody("getting something");
        return response;
    }

    public @ResponseBody BaseResponse<String> getSomethingElse() {
        BaseResponse<String> response = new BaseResponse<String>();
        if (RANDOM.nextBoolean())
            throw new RuntimeException("cannot get something else");
        response.setBody("getting something else");
        return response;
    }
}

错误处理方面:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.BaseError;
import de.scrum_master.app.BaseResponse;
import de.scrum_master.app.ExceptionHandler;

@Aspect
public class ErrorHandler {
    @Around("execution(de.scrum_master.app.BaseResponse<String> *(..))")
    public Object handleError(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        //System.out.println(thisJoinPoint);
        try {
            return thisJoinPoint.proceed();
        } catch (Exception e) {
            BaseError be = ExceptionHandler.errorResponse(e);
            BaseResponse<String> response = new BaseResponse<String>();
            response.setBody("uh-oh!");
            response.setError(be);
            return response;
        }
    }
}

控制台日志:

在这里您可以清楚地看到每个 BaseResponse 是如何由我们的应用程序代码或错误处理方面创建和填充的:

Doing something
BaseResponse [body=getting something, error=OK]
BaseResponse [body=uh-oh!, error=cannot get something else]
Doing something
BaseResponse [body=uh-oh!, error=cannot get something]
BaseResponse [body=getting something else, error=OK]
Doing something
BaseResponse [body=getting something, error=OK]
BaseResponse [body=getting something else, error=OK]
Doing something
BaseResponse [body=getting something, error=OK]
BaseResponse [body=getting something else, error=OK]
Doing something
BaseResponse [body=getting something, error=OK]
BaseResponse [body=uh-oh!, error=cannot get something else]