Spring Boot Interceptor (HandlerInterceptor)
Birçok istekte tekrar eden işler vardır: loglama, süre ölçme, kimlik/yetki kontrolü, istek sayacı, dil ayarı. Bunları her controller metoduna tek tek yazmak hem tekrar hem hata kaynağıdır. Interceptor, Spring MVC sevi…
Spring Boot Interceptor (HandlerInterceptor)
Birçok istekte tekrar eden işler vardır: loglama, süre ölçme, kimlik/yetki kontrolü, istek sayacı, dil ayarı. Bunları her controller metoduna tek tek yazmak hem tekrar hem hata kaynağıdır. Interceptor, Spring MVC seviyesinde isteğin önüne ve arkasına girerek bu ortak işleri tek yerde toplar. Servlet Filter'a benzer ama Spring MVC'ye özeldir (sonraki konuda farkı göreceğiz).
HandlerInterceptor: üç kanca
HandlerInterceptor üç metot sunar:
class ZamanlamaInterceptor implements HandlerInterceptor { boolean preHandle(req, res, handler) { ... return true; } // controller'dan ÖNCE void postHandle(req, res, handler, mav) { ... } // controller SONRASI, view öncesi void afterCompletion(req, res, handler, ex) { ... } // her şey bitince (hata dahil) }
preHandle: Controller metodu çağrılmadan önce.falsedönerse istek controller'a hiç ulaşmaz (örn. yetki yoksa burada kes). İstek başlangıç zamanını koymak, kimlik kontrolü.postHandle: Controller başarıyla döndükten sonra, yanıt render edilmeden önce.afterCompletion: İstek tamamen bittiğinde (başarı veya hata) — kaynak temizleme, süre/durum loglama.
Örnek 1 (./Ornek1.java) her isteğin süresini ve durum kodunu ölçen bir interceptor kurar.
Interceptor'ı kaydetmek
Bir WebMvcConfigurer ile interceptor'ı ekler ve hangi yollara uygulanacağını belirlersin:
@Bean WebMvcConfigurer config() { return new WebMvcConfigurer() { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ZamanlamaInterceptor()) .addPathPatterns("/api/**") // bu yollara uygula .excludePathPatterns("/api/health"); // bunları hariç tut } }; }
Interceptor vs Filter
İkisi de "araya girer" ama farklı seviyelerde (sonraki konu Filter'ı ayrıntılı ele alır):
| Interceptor | Filter (Servlet) | |
|---|---|---|
| Seviye | Spring MVC (DispatcherServlet sonrası) | Servlet konteyneri (daha önce/dışta) |
| Erişim | Handler (controller metodu) bilgisine erişir | Yalnızca ham request/response |
| Kullanım | MVC'ye özgü: yetki, loglama, model ekleme | Genel: CORS, sıkıştırma, kimlik, kodlama |
| Spring bean | Doğal (Spring yönetir) | Bean olabilir ama servlet seviyesinde |
Genel kural: Spring MVC bağlamına (handler, model) ihtiyaç varsa interceptor; tüm isteklerde ham seviyede genel bir iş varsa filter.
Tipik kullanım alanları
- İstek/yanıt loglama ve süre ölçme (gözlemlenebilirlik).
- Kimlik/yetki kontrolü (
preHandle'dafalseile erken kesme). - İstek sayacı / hız sınırlama (rate limiting).
- Ortak model/başlık ekleme, dil (locale) belirleme.
Özet
Interceptor'ın Spring MVC seviyesinde isteğin önüne/arkasına girdiğini; üç kancasını (preHandle
ile erken kesme, postHandle, afterCompletion) ve WebMvcConfigurer ile yol-bazlı kaydı (Örnek 1);
Filter ile farkını ve tipik kullanımları öğrendik. Sırada, daha düşük seviyede (servlet) araya giren
yapı: Servlet Filter.
▶ Kod Örnekleri(1)
Ornek1
ortam gerekir1// Ornek1: HandlerInterceptor — controller'a girmeden önce/sonra araya girmek.
2// Çalıştırma: portal gömülü Tomcat ile başlatır, self-test çıktısını alır.
3package com.egitim.springboot.interceptor;
4
5import jakarta.servlet.http.HttpServletRequest;
6import jakarta.servlet.http.HttpServletResponse;
7import org.springframework.boot.CommandLineRunner;
8import org.springframework.boot.SpringApplication;
9import org.springframework.boot.autoconfigure.SpringBootApplication;
10import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
11import org.springframework.context.annotation.Bean;
12import org.springframework.web.bind.annotation.*;
13import org.springframework.web.client.RestClient;
14import org.springframework.web.servlet.HandlerInterceptor;
15import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
16import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
17
18@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
19public class Ornek1 {
20
21 public static void main(String[] args) { SpringApplication.run(Ornek1.class, args); }
22
23 // Interceptor: Spring MVC seviyesinde, controller metodu ÇAĞRILMADAN önce ve sonra çalışır.
24 static class ZamanlamaInterceptor implements HandlerInterceptor {
25 @Override
26 public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
27 req.setAttribute("baslangic", System.currentTimeMillis());
28 System.out.println(" [interceptor:preHandle] " + req.getMethod() + " " + req.getRequestURI());
29 // false dönerse istek controller'a HİÇ ulaşmaz (örn. yetki yoksa burada kesilir).
30 return true;
31 }
32 @Override
33 public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
34 long sure = System.currentTimeMillis() - (long) req.getAttribute("baslangic");
35 System.out.println(" [interceptor:afterCompletion] durum=" + res.getStatus() + ", süre=" + sure + "ms");
36 }
37 }
38
39 // Interceptor'ı kaydet (hangi yollara uygulanacağını belirle).
40 @Bean
41 WebMvcConfigurer interceptorConfig() {
42 return new WebMvcConfigurer() {
43 @Override public void addInterceptors(InterceptorRegistry registry) {
44 registry.addInterceptor(new ZamanlamaInterceptor())
45 .addPathPatterns("/api/**"); // yalnızca /api/** yollarına uygula
46 }
47 };
48 }
49
50 @RestController
51 @RequestMapping("/api")
52 static class DemoController {
53 @GetMapping("/selam") String selam() { return "merhaba"; }
54 @GetMapping("/veri") java.util.Map<String,Object> veri() { return java.util.Map.of("deger", 42); }
55 }
56
57 @Bean
58 CommandLineRunner selfTest() {
59 return args -> {
60 RestClient c = RestClient.create("http://localhost:8080");
61 System.out.println("\n========= INTERCEPTOR SELF-TEST =========");
62 System.out.println("İstek 1: GET /api/selam");
63 System.out.println(" yanıt -> " + c.get().uri("/api/selam").retrieve().body(String.class));
64 System.out.println("İstek 2: GET /api/veri");
65 System.out.println(" yanıt -> " + c.get().uri("/api/veri").retrieve().body(String.class));
66 System.out.println("(Her istekte interceptor pre/afterCompletion çalıştı.)");
67 System.out.println("=========================================");
68 };
69 }
70}Bu örnek Spring / Spring Boot (Gradle) ortamı gerektirir; tek dosya olarak java Ornek1.java ile çalışmaz. Orijinal portal bunu gömülü Tomcat / Spring context ile koşuyordu. Beklenen davranış yukarıdaki anlatım ve kodda açıklanmıştır.