Spring Boot'ta Control Advice ve Exception Handling konusunu 40 maddede özetleyebilirim. İşte konu hakkında kapsamlı bir açıklama:
Exception handling, uygulamanızda oluşabilecek hataları yönetmek ve ele almak için kullanılır.
Spring Boot, exception handling için @ControllerAdvice ve @ExceptionHandler anotasyonlarını sunar.
@ControllerAdvice, tüm controller'lar için global exception handling sağlar.
@ExceptionHandler, belirli exception türlerini yakalamak ve işlemek için kullanılır.
Bu yapı, hata yönetimini merkezileştirir ve kod tekrarını azaltır.
Özel exception sınıfları oluşturarak, uygulamanıza özgü hataları tanımlayabilirsiniz.
ResponseEntityExceptionHandler sınıfı, yaygın Spring MVC exceptionları için önceden tanımlanmış handler'lar sağlar.
@ResponseStatus anotasyonu, bir exception'a HTTP durum kodu atamak için kullanılır.
ExceptionHandler metodları, Exception nesnesini parametre olarak alabilir.
Bu metodlar, hata mesajlarını özelleştirmek için kullanılabilir.
Farklı exception türleri için farklı HTTP durum kodları döndürebilirsiniz.
@Valid anotasyonu ile yapılan validation hataları da exception handling ile yönetilebilir.
MethodArgumentNotValidException, validation hatalarını yakalamak için kullanılır.
Loglama, exception handling sürecine entegre edilebilir.
Exception handling, REST API'lerde tutarlı hata yanıtları sağlamak için önemlidir.
@RestControllerAdvice, @ControllerAdvice'ın REST-specific versiyonudur.
HandlerExceptionResolver interface'i, özel exception çözümleme mantığı uygulamak için kullanılabilir.
DefaultHandlerExceptionResolver, Spring MVC'nin standart exceptionlarını işler.
SimpleMappingExceptionResolver, exception sınıflarını view isimlerine eşlemek için kullanılabilir.
@ExceptionHandler metodları, ModelAndView döndürerek özel error sayfaları gösterebilir.
Global exception handler'lar, tüm controller'lar için geçerlidir.
Spesifik controller'lar için özel exception handler'lar tanımlanabilir.
Exception handling, güvenlik açısından hassas bilgilerin açığa çıkmasını önlemeye yardımcı olur.
RuntimeException ve checked exception'lar farklı şekillerde ele alınabilir.
@Order anotasyonu, birden fazla @ControllerAdvice sınıfının önceliğini belirlemek için kullanılır.
ErrorController interface'i, özel error handling için uygulanabilir.
Spring Boot Actuator, /error endpoint'i üzerinden hata bilgilerini sunar.
Exception handling, i18n (internationalization) ile entegre edilebilir.
Custom error attributes, ErrorAttributes interface'i implement edilerek tanımlanabilir.
@ControllerAdvice(basePackages = "...") ile belirli paketlere özgü exception handling sağlanabilir.
ExceptionHandlerExceptionResolver, @ExceptionHandler metodlarını çözümler.
ResponseStatusException sınıfı, exception fırlatırken HTTP durum kodunu dinamik olarak belirlemeye olanak tanır.
@RestControllerAdvice, ResponseBody olmadan JSON yanıtları döndürebilir.
ProblemDetail sınıfı, RFC 7807 uyumlu hata yanıtları oluşturmak için kullanılabilir.
@ControllerAdvice sınıfları, farklı ortamlar için farklı şekilde yapılandırılabilir.
Exception handling, unit ve integration testlerde de dikkate alınmalıdır.
AsyncUncaughtExceptionHandler, asenkron metodlardaki exceptionları ele alır.
ExceptionHandler metodları, birden fazla exception türünü ele alabilir.
Nested exceptionlar için özel handling stratejileri uygulanabilir.
Spring Boot'un auto-configuration özelliği, bazı temel exception handling yeteneklerini otomatik olarak yapılandırır.
// 1. Exception handling için temel yapı
@ControllerAdvice
public class GlobalExceptionHandler {
// Exception handling metodları burada yer alacak
}
// 2. @ControllerAdvice kullanımı
@ControllerAdvice
public class GlobalExceptionHandler {
// Bu sınıf, tüm controller'lar için global exception handling sağlar
}
// 3. @ExceptionHandler kullanımı
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return new ResponseEntity<>("Bir hata oluştu: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 4. Belirli bir exception türünü yakalamak
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointerException(NullPointerException e) {
return new ResponseEntity<>("Null değer hatası: " + e.getMessage(), HttpStatus.BAD_REQUEST);
}
}
// 5. Hata yönetimini merkezileştirme örneği
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAllExceptions(Exception e) {
// Tüm exceptionlar burada merkezi olarak yönetilir
return new ResponseEntity<>("Genel hata: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 6. Özel exception sınıfı oluşturma
public class CustomBusinessException extends RuntimeException {
public CustomBusinessException(String message) {
super(message);
}
}
// 7. ResponseEntityExceptionHandler kullanımı
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
// Bu sınıf, yaygın Spring MVC exceptionları için önceden tanımlanmış handler'lar sağlar
}
// 8. @ResponseStatus kullanımı
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
// 9. Exception nesnesini parametre olarak alma
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomBusinessException.class)
public ResponseEntity<String> handleCustomException(CustomBusinessException e) {
return new ResponseEntity<>("İş mantığı hatası: " + e.getMessage(), HttpStatus.BAD_REQUEST);
}
}
// 10. Hata mesajlarını özelleştirme
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e) {
ErrorResponse error = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Bir hata oluştu",
e.getMessage()
);
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// ErrorResponse sınıfı
public class ErrorResponse {
private int status;
private String message;
private String details;
// Constructor, getter ve setter metodları
}
// 11. Farklı exception türleri için farklı HTTP durum kodları
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException e) {
ErrorResponse error = new ErrorResponse("Kaynak bulunamadı", e.getMessage());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
ErrorResponse error = new ErrorResponse("Geçersiz argüman", e.getMessage());
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}
// 12. @Valid anotasyonu ile validation hatalarını yönetme
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
// User oluşturma işlemleri
return new ResponseEntity<>(user, HttpStatus.CREATED);
}
}
// 13. MethodArgumentNotValidException'ı yakalama
@ControllerAdvice
public class ValidationExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
// 14. Exception handling'e loglama ekleme
@ControllerAdvice
public class LoggingExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(LoggingExceptionHandler.class);
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
logger.error("Bir hata oluştu: ", e);
return new ResponseEntity<>("Bir hata oluştu, lütfen daha sonra tekrar deneyin.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 15. REST API'ler için tutarlı hata yanıtları
@ControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiError> handleException(Exception e) {
ApiError apiError = new ApiError(
HttpStatus.INTERNAL_SERVER_ERROR,
"Bir hata oluştu",
e.getMessage()
);
return new ResponseEntity<>(apiError, apiError.getStatus());
}
}
// ApiError sınıfı
public class ApiError {
private HttpStatus status;
private String message;
private String debugMessage;
// Constructor, getter ve setter metodları
}
// 16. @RestControllerAdvice kullanımı
@RestControllerAdvice
public class GlobalRestExceptionHandler {
@ExceptionHandler(Exception.class)
public ApiError handleException(Exception e) {
return new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, "Bir hata oluştu", e.getMessage());
}
}
// 17. HandlerExceptionResolver interface'ini uygulama
public class CustomHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("exception", ex.getMessage());
return mav;
}
}
// 18. DefaultHandlerExceptionResolver kullanımı
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
super.configureHandlerExceptionResolvers(exceptionResolvers);
}
}
// 19. SimpleMappingExceptionResolver kullanımı
@Configuration
public class ExceptionConfig {
@Bean
public SimpleMappingExceptionResolver exceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties mappings = new Properties();
mappings.setProperty("DatabaseException", "databaseError");
mappings.setProperty("InvalidCreditCardException", "creditCardError");
resolver.setExceptionMappings(mappings);
resolver.setDefaultErrorView("error");
return resolver;
}
}
// 20. ModelAndView ile özel error sayfaları gösterme
@ControllerAdvice
public class CustomErrorController {
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception e) {
ModelAndView mav = new ModelAndView("customError");
mav.addObject("errorMessage", "Bir hata oluştu: " + e.getMessage());
return mav;
}
}
// 21. Global exception handler örneği
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex, WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
ex.getMessage(),
request.getDescription(false));
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 22. Spesifik controller için özel exception handler
@RestController
@RequestMapping("/api/users")
public class UserController {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ErrorResponse> handleUserNotFoundException(UserNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
"Kullanıcı bulunamadı",
ex.getMessage());
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
}
// 23. Güvenlik açısından hassas bilgileri gizleme
@ControllerAdvice
public class SecurityAwareExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"Bir hata oluştu",
"Detaylı hata bilgisi gizlendi");
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 24. RuntimeException ve checked exception'ları farklı şekilde ele alma
@ControllerAdvice
public class DifferentExceptionTypeHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
return new ResponseEntity<>("Runtime hatası: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleCheckedException(Exception ex) {
return new ResponseEntity<>("Checked exception: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
// 25. @Order anotasyonu ile öncelik belirleme
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HighPriorityExceptionHandler {
@ExceptionHandler(HighPriorityException.class)
public ResponseEntity<String> handleHighPriorityException(HighPriorityException ex) {
return new ResponseEntity<>("Yüksek öncelikli hata: " + ex.getMessage(), HttpStatus.CRITICAL);
}
}
// 26. ErrorController interface'ini uygulama
@Controller
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public String handleError() {
return "error";
}
public String getErrorPath() {
return "/error";
}
}
// 27. Spring Boot Actuator ile /error endpoint'i kullanımı
@RestController
public class ActuatorErrorController {
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping("/error")
public Map<String, Object> handleError(WebRequest webRequest) {
Map<String, Object> errorAttributes = this.errorAttributes.getErrorAttributes(webRequest, ErrorAttributeOptions.of(ErrorAttributeOptions.Include.STACK_TRACE));
return errorAttributes;
}
}
// 28. i18n ile entegre exception handling
@ControllerAdvice
public class I18nAwareExceptionHandler {
@Autowired
private MessageSource messageSource;
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex, Locale locale) {
String errorMessage = messageSource.getMessage("error.general", null, locale);
return new ResponseEntity<>(errorMessage, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 29. Custom error attributes tanımlama
@Component
public class CustomErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
errorAttributes.put("custom_attribute", "Bu özel bir hata özniteliğidir");
return errorAttributes;
}
}
// 30. Belirli paketlere özgü exception handling
@ControllerAdvice(basePackages = "com.example.myapp.controllers")
public class SpecificPackageExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return new ResponseEntity<>("Bu hata yalnızca belirli bir paketteki controller'lar için yakalandı: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 31. ExceptionHandlerExceptionResolver kullanımı
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
ExceptionHandlerExceptionResolver exceptionHandlerResolver = new ExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setMessageConverters(getMessageConverters());
exceptionHandlerResolver.afterPropertiesSet();
exceptionResolvers.add(exceptionHandlerResolver);
}
}
// 32. ResponseStatusException kullanımı
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Kullanıcı bulunamadı");
}
return user;
}
}
// 33. @RestControllerAdvice ile JSON yanıtları
@RestControllerAdvice
public class GlobalRestExceptionHandler {
@ExceptionHandler(Exception.class)
public ErrorResponse handleException(Exception ex) {
return new ErrorResponse("Bir hata oluştu", ex.getMessage());
}
}
// 34. ProblemDetail kullanımı (Spring Framework 6.0+)
@RestControllerAdvice
public class ProblemDetailExceptionHandler {
@ExceptionHandler(Exception.class)
public ProblemDetail handleException(Exception ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
problemDetail.setTitle("Bir hata oluştu");
return problemDetail;
}
}
// 35. Farklı ortamlar için farklı exception handling
@ControllerAdvice
@Profile("production")
public class ProductionExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return new ResponseEntity<>("Bir hata oluştu", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
@ControllerAdvice
@Profile("development")
public class DevelopmentExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
return new ResponseEntity<>("Hata: " + ex.getMessage() + "\n" + Arrays.toString(ex.getStackTrace()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 36. Exception handling için unit test
@ExtendWith(SpringExtension.class)
@WebMvcTest(UserController.class)
public class UserControllerExceptionTest {
@Autowired
private MockMvc mockMvc;
@Test
public void whenUserNotFound_thenReturns404() throws Exception {
mockMvc.perform(get("/api/users/999"))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.message").value("Kullanıcı bulunamadı"));
}
}
// 37. AsyncUncaughtExceptionHandler kullanımı
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
}
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
System.out.println("Async metod exception: " + ex.getMessage());
}
}
// 38. Birden fazla exception türünü ele alma
@ControllerAdvice
public class MultipleExceptionHandler {
@ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class})
public ResponseEntity<String> handleMultipleExceptions(Exception ex) {
return new ResponseEntity<>("Geçersiz argüman veya durum: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
// 39. Nested exceptionlar için özel handling
@ControllerAdvice
public class NestedExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) {
Throwable rootCause = getRootCause(ex);
return new ResponseEntity<>("Kök neden: " + rootCause.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
private Throwable getRootCause(Throwable throwable) {
Throwable rootCause = throwable;
while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
rootCause = rootCause.getCause();
}
return rootCause;
}
}
// 40. Spring Boot'un auto-configuration özelliği
// Bu özellik otomatik olarak çalışır, özel bir kod gerektirmez.
// Ancak, özelleştirmek isterseniz:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
resolvers.add(new DefaultHandlerExceptionResolver());
// Diğer özel çözümleyicileri buraya ekleyebilirsiniz
}
}