如果你想拦截异常,你可以在你的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>
|