一 背景
日常开发中,我们通常基于@ControllerAdivce和springboot的ErrorController对代码中抛出的异常进行统一的拦截,返回统一的格式,但是随着业务的持续迭代升级,对不同场景下的异常业务有不同的处理,比如有点异常需要国际化,有的异常需要消息通知,如果都同一拦截处理不同的异常会导致改拦截体中的方法越来越多.
本文针对上述场景基于策略模式,构造者模式等实现对异常处理统一封装,并作为springboot的自定义starter
二 整体实现思路

- 将异常的处理统一抽象成ExceptionTranslator接口,根据不同的业务实现适配不同的业务异常
- 将不同的业务实现注册到ExceptionTranslatorRegister中
- handler中依赖ExceptionTranslatorExecutor
- ExceptionTranslatorExecutor中调用注册到ExceptionTranslatorRegister中的ExceptionTranslator对遍历适配到相应的翻译器对当前异常进行翻译
三 代码实现
定义异常翻译接口
public interface Support {
    /**
     * 是否支持当前异常
     * @param throwable
     * @return
     */
    Boolean support(Throwable throwable);
}
public interface ExceptionTranslator extends Support {
    /**
     * 异常翻译
     * @param throwable
     * @return
     */
    ApiResult translate(Throwable throwable);
}
抽象实现
@Slf4j
public abstract class AbstractExceptionTranslator implements ExceptionTranslator, InitializingBean {
    @Override
    public ApiResult translate(Throwable throwable) {
        if (!support(throwable)){
            log.info("{} not support for {}", this.getClass().getName(), throwable.toString());
            return null;
        }
        log.info("{} will be handled by {}.", throwable.toString(), this.getClass().getSimpleName());
        return doTranslate(throwable);
    }
    /**
     * 注入实例化bean中的翻译器
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        ExceptionTranslatorRegister.register(this);
    }
    /**
     * 实例的实现
     * @param throwable
     * @return
     */
    protected abstract ApiResult doTranslate(Throwable throwable);
}
不同异常实现
public class CommonBusinessExceptionTranslator extends AbstractExceptionTranslator {
    @Override
    protected ApiResult doTranslate(Throwable throwable) {
        return ApiResultBuildr.build(GlobalErrorConstants.INTERNAL_SERVER_ERROR.getCode(), throwable.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
    @Override
    public Boolean support(Throwable throwable) {
        return throwable instanceof BaseBusinessException;
    }
}
public class UnsupportedExceptionTranslator extends AbstractExceptionTranslator {
    @Override
    protected ApiResult doTranslate(Throwable throwable) {
        return ApiResultBuildr.build(GlobalErrorConstants.INTERNAL_SERVER_ERROR.getCode(), GlobalErrorConstants.INTERNAL_SERVER_ERROR.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
    @Override
    public Boolean support(Throwable throwable) {
        return true;
    }
}
统一注册
@Slf4j
public class ExceptionTranslatorRegister {
    private static final Collection<ExceptionTranslator> EXCEPTION_TRANSLATORS = Collections.synchronizedSet(new LinkedHashSet<>());
    /**
     * 初始化默认的翻译器
     */
    static  {
        /**
         * 系统调用链反向顺序(顺序有关优先级)
         */
        register(new UnsupportedExceptionTranslator());
        register(new CommonBusinessExceptionTranslator());
        register(new LocalBusinessExceptionTranslator());
        //web mvc
        register(new HttpMethodNotSupportedExceptionTranslator());
        register(new MethodArgumentNotValidExceptionTranslator());
        register(new WebBindingExceptionTranslator());
        register(new ValidationExceptionTranslator());
        register(new NoHandlerFoundExceptionTranslator());
        register(new RequestNotMappingExceptionTranslator());
        register(new ConstraintViolationExceptionTranslator());
        register(new ServletRequestBindingExceptionTranslator());
    }
    public static boolean register(ExceptionTranslator exceptionTranslator) {
        return EXCEPTION_TRANSLATORS.add(exceptionTranslator);
    }
    public static Collection<ExceptionTranslator> getAll() {
        List<ExceptionTranslator> temp = new ArrayList<>(EXCEPTION_TRANSLATORS);
        Collections.reverse(temp);
        log.debug("current registered exception translators: {}", temp);
        return Collections.unmodifiableCollection(temp);
    }
}

定义执行器
@Slf4j
public class ExceptionTranslatorExecutor implements ExceptionTranslator {
    @Override
    public ApiResult translate(Throwable throwable) {
        log.error("error: ", throwable);
        for (ExceptionTranslator translator: ExceptionTranslatorRegister.getAll()) {
            if (!translator.support(throwable)) {
                continue;
            }
            ApiResult apiResult = translator.translate(throwable);
            if (apiResult != null) {
                return apiResult;
            }
        }
        log.warn("none exception translator matched. default result returned.");
        return ApiResultBuildr.build(GlobalErrorConstants.INTERNAL_SERVER_ERROR.getCode(), GlobalErrorConstants.INTERNAL_SERVER_ERROR.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
    @Override
    public Boolean support(Throwable throwable) {
        return Boolean.TRUE;
    }
}
拦截器中调用
@RequestMapping("${server.error.path:${error.path:/error}}")
public class GlobalExceptionController extends BasicErrorController {
    private final ExceptionTranslator exceptionTranslator;
    private final ErrorAttributes errorAttributes;
    public GlobalExceptionController(ExceptionTranslator exceptionTranslator, ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
        super(errorAttributes, errorProperties);
        this.errorAttributes = errorAttributes;
        this.exceptionTranslator = exceptionTranslator;
    }
    @Override
    @RequestMapping
    @ResponseBody
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        LocalResult localResult;
        HttpStatus httpStatus = getStatus(request);
        if (httpStatus.equals(HttpStatus.NOT_FOUND)) {
            localResult = new LocalResult();
            localResult.setCode(httpStatus.value());
            localResult.setMessage(GlobalErrorConstants.NOT_FOUND.getMessage());
        } else {
            ServletWebRequest servletWebRequest = new ServletWebRequest(request);
            Throwable error = errorAttributes.getError(servletWebRequest);
            if (error != null) {
                error = ExceptionUtil.getRootCause(error);
                ApiResult translate = exceptionTranslator.translate(error);
                localResult = translate.getBody();
                httpStatus = translate.getHttpStatus();
            } else {
                localResult = new LocalResult();
                localResult.setCode(httpStatus.value());
                localResult.setMessage(GlobalErrorConstants.INTERNAL_SERVER_ERROR.getMessage());
            }
        }
        Map<String, Object> body = BeanUtil.beanToMap(localResult);
        return new ResponseEntity<>(body, httpStatus);
    }
}
@RestControllerAdvice
public class GlobalExceptionHandler {
    private final ExceptionTranslator exceptionTranslator;
    public GlobalExceptionHandler(ExceptionTranslator exceptionTranslator) {
        this.exceptionTranslator = exceptionTranslator;
    }
    @ExceptionHandler(Exception.class)
    public ResponseEntity<LocalResult> handleException(Exception e) {
        return exceptionTranslator.translate(e).toResponseEntity();
    }
}
bean注入
public class ExceptionConfig {
    /**
     * 翻译执行器
     * @return
     */
    @ConditionalOnMissingBean
    @Bean
    public ExceptionTranslator exceptionTranslator() {
        return new ExceptionTranslatorExecutor();
    }
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)
    @Bean
    public GlobalExceptionController globalExceptionController(ExceptionTranslator exceptionTranslator, ErrorAttributes errorAttributes, ServerProperties serverProperties) {
        return new GlobalExceptionController(exceptionTranslator, errorAttributes, serverProperties.getError());
    }
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    @ConditionalOnClass(DispatcherServlet.class)
    @Bean
    public GlobalExceptionHandler globalExceptionHandler(ExceptionTranslator exceptionTranslator) {
        return new GlobalExceptionHandler(exceptionTranslator);
    }
}
@Configuration
@Import({ExceptionConfig.class})
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
public class ExceptionHandlerAutoConfiguration {
}

 
                   
                   
                   
                   
                             
                     
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1万+
					1万+
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            