【问题标题】:How to get rid of try/catch method inside every method如何摆脱每个方法中的 try/catch 方法
【发布时间】:2016-07-20 14:11:47
【问题描述】:

我有很多rest服务的应用,大部分都遵循这个模式:

class RestService{

   public Response execute1() {
      try{
         // doLogicThere...

         return response;
       } catch () {
         // handle exception and build Response object..

         return response;
       }
   }

   public Response execute2() {
       try{
          // doLogicThere...

          return response;
       } catch() {
          // handle exception and build Response object..

          return response;
       }
   }
}

catch 子句对于所有方法都是相同的,所以我想在下面有这样的模式,但是从其他地方调用 try/catch。我想做一些包装这些方法。

class RestService{

    public Response execute1() {
        // doLogicThere...

        return response;
    }

    public Response execute2() {
       // doLogicThere...

       return response;
    }
}

【问题讨论】:

标签: java spring try-catch aop


【解决方案1】:

JAX-WS 包含一种机制,用于为您的 REST 方法可能产生的每种异常类型创建适当的响应。

对于每种异常类型,创建一个实现ExceptionMapper<E> 的类,其中E 是异常类型。您在 toResponse 方法中创建您的响应。您需要使用 @Provider 注释您的异常映射器,以便将其注册到 JAX-RS 运行时。

@Provider
public class UserNotFoundMapper implements ExceptionMapper<UserNotFoundException> {
    @Override
    public Response toResponse(UserNotFoundException e) {
        return Response.status(404).entity(e.getMessage()).type("text/plain").build();
    }
}

【讨论】:

  • 这是我的第一次拍摄。不幸的是,我正在处理此提供程序的注册,因为我正在使用我的自定义 Web 应用程序容器。在某些情况下,您必须手动注册提供程序,就像您有时为 JacksonJsonProvider 所做的那样。
【解决方案2】:

您可以使用您需要执行的方法创建一个接口。然后,您可以将该方法包装在新方法中的 try catch 中。这将避免使用许多重复的 try catch 块。

你可以这样做:

public interface CallableClass {
    public Response call();
}



...

class RestService {
    private Response handleCall(CallableClass myClass) {
        try {
            return myClass.call();
        } catch (Exception e) {
            // Handle exception and return a particular response
            ...
        }
    }

    public Response execute1() {
        return handleCall(/* put anonymous class of type CallableClass here */); 
    }

    public Response execute2() {
        return handleCall(/* put anonymous class of type CallableClass here */); 
    }

}

如果您使用的是 java 8,则可以将匿名类替换为更优雅的 lambda 表达式。


这里是一个简单的 lambda 示例

public Response executeLambda() {
    return handleCall(() -> {
        ... // Your code here
        return response;
    });
}

【讨论】:

  • 你能举个例子吗?
  • @jimpudar 我在答案中添加了一个简单的例子
【解决方案3】:

您可以使用“throws”关键字来指示方法抛出某些异常。然后,当您调用该方法时,您可以简单地将调用包装在 try/catch 块中。

见:https://docs.oracle.com/javase/tutorial/essential/exceptions/declaring.html

【讨论】:

    【解决方案4】:

    如果您使用 SPring MVC 构建 RESTFul 服务,则可以更好地选择使用以下注释“@ExceptionHandler(CustomExceptionForRestServices.class)”。您可以在其中编写 customException 或使用逗号分隔的您希望方法抛出的异常类列表。

    @ExceptionHandler 值可以设置为异常类型数组。如果抛出的异常与列表中的类型之一匹配,则将调用使用匹配的 @ExceptionHandler 注释的方法。如果未设置注释值,则使用作为方法参数列出的异常类型。

    与使用@RequestMapping 注解注解的标准控制器方法很相似,@ExceptionHandler 方法的方法参数和返回值非常灵活。

    【讨论】:

      【解决方案5】:

      我在普通的 AspectJ 中创建了一个小例子,即没有任何 Spring。我什至创建了一个虚拟的Response 类,以展示方面驱动的异常处理背后的基本机制:

      虚拟响应类:

      package de.scrum_master.app;
      
      public class Response {
          private int statusCode;
          private String message;
      
          public Response(int statusCode) {
              this.statusCode = statusCode;
              switch (statusCode) {
              case 200:
                  message = "OK";
                  break;
              case 202:
                  message = "Accepted";
                  break;
              case 401:
                  message = "Unauthorized";
                  break;
              default:
                  message = "Unknown status";
              }
          }
      
          public int getStatusCode() {
              return statusCode;
          }
      
          @Override
          public String toString() {
              return "Response(statusCode=" + statusCode + ", message=" + message + ")";
          }
      }
      

      有两种方法被拦截的驱动应用:

      如您所见,这两种方法都会随机抛出异常,这些异常应该稍后被方面捕获。

      package de.scrum_master.app;
      
      import java.util.Random;
      
      public class RestService {
          private static final Random RANDOM = new Random();
      
          public Response someRequest() {
              Response response = new Response(RANDOM.nextBoolean() ? 200 : 401);
              if (response.getStatusCode() != 200)
                  throw new RuntimeException("request failed: " + response);
              return response;
          }
      
          public Response anotherRequest(String argument) {
              Response response = new Response(RANDOM.nextBoolean() ? 200 : 401);
              if (response.getStatusCode() != 200)
                  throw new RuntimeException("request failed: " + response);
              return response;
          }
      
          public static void main(String[] args) {
              RestService restService = new RestService();
              for (int i = 0; i < 3; i++) {
                  System.out.println(restService.someRequest());
                  System.out.println(restService.anotherRequest("foo"));
              }
          }
      }
      

      异常处理方面:

      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.Response;
      
      @Aspect
      public class ResponseErrorHandler {
          @Around("execution(de.scrum_master.app.Response *(..))")
          public Response handleError(ProceedingJoinPoint thisJoinPoint) {
              System.out.println("\n" + thisJoinPoint);
              try {
                  return (Response) thisJoinPoint.proceed();
              }
              catch (Exception e) {
                  System.out.println("  Handling exception: " + e.getMessage());
                  return new Response(202);
              }
          }
      }
      

      控制台日志:

      execution(Response de.scrum_master.app.RestService.someRequest())
      Response(statusCode=200, message=OK)
      
      execution(Response de.scrum_master.app.RestService.anotherRequest(String))
      Response(statusCode=200, message=OK)
      
      execution(Response de.scrum_master.app.RestService.someRequest())
      Response(statusCode=200, message=OK)
      
      execution(Response de.scrum_master.app.RestService.anotherRequest(String))
        Handling exception: request failed: Response(statusCode=401, message=Unauthorized)
      Response(statusCode=202, message=Accepted)
      
      execution(Response de.scrum_master.app.RestService.someRequest())
      Response(statusCode=200, message=OK)
      
      execution(Response de.scrum_master.app.RestService.anotherRequest(String))
        Handling exception: request failed: Response(statusCode=401, message=Unauthorized)
      Response(statusCode=202, message=Accepted)
      

      如果您不明白答案,请随时提出后续问题。

      【讨论】:

        猜你喜欢
        • 2010-09-21
        • 1970-01-01
        • 1970-01-01
        • 2012-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-17
        • 1970-01-01
        相关资源
        最近更新 更多