面试题答案
一键面试异常处理机制避免成为性能瓶颈的思路
- 使用通用异常处理器:在Spring等框架中,使用
@ControllerAdvice
注解定义全局异常处理器,避免在每个API方法中重复编写异常处理代码,提高代码的可维护性和性能。例如:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<String> handleException(Exception ex) {
// 处理异常逻辑
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred");
}
}
- 合理使用缓存:
- 缓存异常处理结果:对于一些频繁发生且处理结果固定的异常(如参数校验异常等),可以缓存异常处理后的响应信息。例如使用Guava Cache:
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
// 构建异常处理结果
return "Cached error response for " + key;
}
});
- **异常处理过程中避免不必要的缓存操作**:确保在异常处理时,不会因为过度依赖缓存获取数据而导致性能下降。例如,如果缓存不可用,异常处理逻辑应能快速降级,而不是长时间等待缓存恢复。
3. 线程池的应用:
- 异步处理异常日志记录:将异常日志记录等I/O密集型操作放到线程池中异步执行,避免阻塞主线程。例如使用Java的ThreadPoolExecutor
:
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(() -> {
// 记录异常日志
logger.error("Exception occurred", ex);
});
- **合理配置线程池参数**:根据系统的硬件资源(如CPU核心数、内存大小)和业务负载,合理设置线程池的核心线程数、最大线程数、队列容量等参数,避免线程过多导致的上下文切换开销或队列溢出问题。
4. 异常日志记录:
- 使用异步日志框架:如Log4j 2的异步日志记录功能,它使用AsyncAppender
或AsyncLogger
来实现异步日志记录。这样主线程在抛出异常时可以快速返回,而日志记录在后台线程中进行。
- 控制日志级别:在生产环境中,设置合适的日志级别(如INFO
、WARN
、ERROR
),避免记录过多不必要的日志信息,减少I/O开销。例如,只在ERROR
级别记录异常详细信息。
- 日志格式优化:采用简洁且易于解析的日志格式,如JSON格式,便于后续使用日志分析工具进行问题定位,同时减少日志记录时的格式化开销。例如:
{
"timestamp": "2023-10-01T12:00:00Z",
"level": "ERROR",
"message": "Exception occurred: IllegalArgumentException",
"exception": "java.lang.IllegalArgumentException: invalid parameter value",
"thread": "http-nio-8080-exec-1"
}