如果你想拦截异常,你可以在你的Springboot应用程序中定义一个统一的异常处理器来实现。
例如,你可以使用@ControllerAdvice注解来定义一个异常处理器,然后使用@ExceptionHandler注解来指定拦截哪些异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
   | 
 
 
 
 
  @RestControllerAdvice public class GlobalExceptionHandler {     private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
      
 
      @ExceptionHandler(BaseException.class)     public AjaxResult baseException(BaseException e) {         return AjaxResult.error(e.getDefaultMessage());     }
      
 
      @ExceptionHandler(CustomException.class)     public AjaxResult businessException(CustomException e) {         if (StringUtils.isNull(e.getCode())) {             return AjaxResult.error(e.getMessage());         }         return AjaxResult.error(e.getCode(), e.getMessage());     }
      @ExceptionHandler(Exception.class)     public AjaxResult handleException(Exception e) {         log.error(e.getMessage(), e);         return AjaxResult.error(e.getMessage());     }
      
 
      @ExceptionHandler(BindException.class)     public AjaxResult validatedBindException(BindException e) {         log.error(e.getMessage(), e);         String message = e.getAllErrors().get(0).getDefaultMessage();         return AjaxResult.error(message);     }
      
 
      @ExceptionHandler(MethodArgumentNotValidException.class)     public Object validExceptionHandler(MethodArgumentNotValidException e) {         log.error(e.getMessage(), e);         String message = e.getBindingResult().getFieldError().getDefaultMessage();         return AjaxResult.error(message);     }
      
 
      @ExceptionHandler(PreAuthorizeException.class)     public AjaxResult preAuthorizeException() {         return AjaxResult.error("没有权限,请联系管理员授权");     }
      
 
      @ExceptionHandler(DemoModeException.class)     public AjaxResult demoModeException() {         return AjaxResult.error("演示模式,不允许操作");     }
      @ExceptionHandler(DuplicateKeyException.class)     public AjaxResult duplicateKeyHandler() {         return AjaxResult.error("数据已存在,请勿重复提交");     }
      @ExceptionHandler(DataAccessException.class)     public AjaxResult dataAccessException(DataAccessException e) {         log.error("JDBC异常:" + e.getMessage(), e);         return AjaxResult.error("系统错误,请联系管理员!");     }
      @ExceptionHandler(HttpMessageNotReadableException.class)     public AjaxResult httpMessageNotReadableException(HttpMessageNotReadableException e) {         log.error("Http请求参数转换异常:" + e.getMessage(), e);         return AjaxResult.error("系统错误,请联系管理员!");     } }
 
  | 
 
在这个例子中,我们定义了一个名为GlobalExceptionHandler的异常处理器,并使用@ExceptionHandler注解来指定要拦截的异常类型。这样,当应用程序中发生Exception类型的异常时,该异常处理器就会被调用。
在异常处理器的方法中,你可以自定义如何处理这些异常。例如,你可以将异常信息记录到日志中,或者向用户展示一个错误消息,或者返回一个错误页面等。
总之,使用异常处理器是一种比较简单和优雅的方式来拦截异常,并对其进行统一处理。
@ControllerAdvice和@RestControllerAdvice的区别
@ControllerAdvice注解和@RestControllerAdvice注解都可以用于定义一个异常处理器,但它们之间有一些区别:
@ControllerAdvice注解可以用于处理所有带有@Controller注解的控制器中的异常。这种类型的异常处理器通常用于处理Web应用程序中的异常,并向用户展示一个错误页面。
@RestControllerAdvice注解可以用于处理所有带有@RestController注解的控制器中的异常。这种类型的异常处理器通常用于处理RESTful接口中的异常,并将错误信息以JSON格式返回给客户端。
总之,@ControllerAdvice注解和@RestControllerAdvice注解都可以用于定义一个异常处理器,但它们的使用场景不同,应根据实际情况来选择合适的注解。
如果你在微服务应用程序中定义了一个带有@ControllerAdvice注解的异常处理器,但它并没有被调用,那么可能是因为以下几种原因
- 异常处理器类上没有使用@ControllerAdvice注解:如果你的异常处理器类上没有使用@ControllerAdvice注解,那么它就不会被识别为一个异常处理器,因此也不会被调用。
 
- 异常处理方法上没有使用@ExceptionHandler注解:如果你的异常处理方法上没有使用@ExceptionHandler注解,那么它就不会被识别为一个异常处理方法,因此也不会被调用。
 
- 异常处理方法没有指定要处理的异常类型:如果你的异常处理方法没有指定要处理的异常类型,那么它就不会被调用。例如,如果你的异常处理方法只处理IOException类型的异常,那么如果应用程序中发生的异常不是IOException类型,那么这个方法就不会被调用。
 
总之,如果你定义的异常处理器没有被调用,那么最可能的原因就是你的异常处理器类没有使用@ControllerAdvice
日志异步线程池入库
线程池配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
   | 
 
 
 
  @Configuration public class AsyncConfig {
      private static final Logger log = LoggerFactory.getLogger(AsyncConfig.class);
      @Bean("asyncTaskExecutor")     public AsyncTaskExecutor asyncTaskExecutor() {
          ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();                  executor.setCorePoolSize(10);                  executor.setMaxPoolSize(50);                  executor.setQueueCapacity(500);                  executor.setKeepAliveSeconds(60);                  executor.setThreadNamePrefix("async-task-thread-pool-");                  executor.setAllowCoreThreadTimeOut(true);                  executor.setTaskDecorator(new ContextCopyingDecorator());                  executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());         executor.initialize();         return executor;     }
      static class ContextCopyingDecorator implements TaskDecorator {         @Override         public Runnable decorate(Runnable runnable) {
              log.info("父线程:{}", Thread.currentThread());                          AsyncSecurityUtils.setThreadLocal();             ThreadContextHolder parentContextHolder = ThreadContextHolder.getInstance();             Map<String, String> cloneMap = cloneMap(parentContextHolder.getContext());             parentContextHolder.clear();             return () -> {                 ThreadContextHolder childContextHolder = ThreadContextHolder.getInstance();                 try {                     log.info("子线程:{}", Thread.currentThread());                     childContextHolder.setContext(cloneMap);                     runnable.run();                 } finally {                                          childContextHolder.clear();                 }             };         }     }
      private static Map<String, String> cloneMap(Map<String, String> map) {         if (map != null) {             return new HashMap<>(map);         } else {             return null;         }     } }
 
  | 
 
线程绑定信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
   | public class ThreadContextHolder {
      public Logger log = LoggerFactory.getLogger(ThreadContextHolder.class);
      private final ThreadLocal<Map<String, String>> threadLocal;
      private ThreadContextHolder() {         this.threadLocal = new ThreadLocal<>();     }
      
 
      public static ThreadContextHolder getInstance() {         return SingletonHolder.S_INSTANCE;     }
      
 
 
      private static class SingletonHolder {         private static final ThreadContextHolder S_INSTANCE = new ThreadContextHolder();     }
      
 
 
 
      public void setContext(Map<String, String> map) {         threadLocal.set(map);     }
      
 
 
 
      public Map<String, String> getContext() {         return threadLocal.get();     }
      
 
      public void clear() {         threadLocal.remove();     } }
  | 
 
异步调用日志服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | @Service public class AsyncLogService {     @Autowired     private RemoteLogService remoteLogService;
      
 
      @Async("asyncTaskExecutor")     public void saveSysLog(SysOperLog sysOperLog)     {                  remoteLogService.saveLog(sysOperLog);     } }
 
   | 
 
Logback输出日志到自定义MySQL数据库
在你的项目中添加Logback的依赖,并在classpath下创建一个名为”logback.xml”的配置文件,其内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | <?xml version="1.0" encoding="UTF-8"?> <configuration>     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">         <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">             <driverClass>com.mysql.jdbc.Driver</driverClass>             <url>jdbc:mysql://localhost:3306/logging?useSSL=false</url>             <user>username</user>             <password>password</password>         </connectionSource>     </appender>     <root level="info">         <appender-ref ref="DB" />     </root> </configuration>
   |