← Назад к вопросам

Что такое Interceptor в Java?

1.0 Junior🔥 181 комментариев
#Soft Skills и карьера

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Interceptor в Java

Определение

Interceptor — это паттерн проектирования, который позволяет обработать (перехватить) запрос до попадания в целевой объект или после получения ответа от него. Interceptor позволяет добавлять функциональность без изменения исходного кода.

Существуют Interceptors в разных контекстах Java:

  • HTTP Interceptors (OkHttp, Spring)
  • Servlet Filters (J2EE)
  • AOP Proxies (Spring AOP)
  • Handlers в HTTP клиентах

HTTP Interceptor в OkHttp

OkHttp — популярная библиотека для HTTP запросов, имеет встроенный Interceptor интерфейс:

public interface Interceptor {
    Response intercept(Chain chain) throws IOException;
    
    interface Chain {
        Request request();
        Response proceed(Request request) throws IOException;
    }
}

Пример: Логирование всех HTTP запросов

public class LoggingInterceptor implements Interceptor {
    private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        
        long startTime = System.nanoTime();
        logger.info("Sending request: {} {}", request.method(), request.url());
        
        // Печатаем headers запроса
        for (String header : request.headers().names()) {
            logger.info("{}: {}", header, request.header(header));
        }
        
        try {
            Response response = chain.proceed(request);
            
            long endTime = System.nanoTime();
            long duration = (endTime - startTime) / 1000000;
            
            logger.info("Received response: {} in {}ms", 
                response.code(), duration);
            logger.info("Content-Type: {}", response.header("content-type"));
            
            return response;
        } catch (IOException e) {
            long endTime = System.nanoTime();
            long duration = (endTime - startTime) / 1000000;
            logger.error("Request failed: {} in {}ms", 
                request.url(), duration, e);
            throw e;
        }
    }
}

// Использование
OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .build();

Request request = new Request.Builder()
    .url("https://api.example.com/users")
    .build();

Response response = client.newCall(request).execute();

HTTP Interceptor в Spring RestTemplate

Spring предоставляет ClientHttpRequestInterceptor для перехвата запросов:

public class AuthTokenInterceptor implements ClientHttpRequestInterceptor {
    private final TokenService tokenService;
    
    public AuthTokenInterceptor(TokenService tokenService) {
        this.tokenService = tokenService;
    }
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
            ClientHttpRequestExecution execution) throws IOException {
        
        // Получаем токен и добавляем в заголовок
        String token = tokenService.getAccessToken();
        request.getHeaders().setBearerAuth(token);
        
        // Продолжаем с модифицированным запросом
        ClientHttpResponse response = execution.execute(request, body);
        
        // Обработка ответа
        if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
            // Можем обновить токен и повторить запрос
            token = tokenService.refreshToken();
            request.getHeaders().setBearerAuth(token);
            response = execution.execute(request, body);
        }
        
        return response;
    }
}

// Конфигурация
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(TokenService tokenService) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(new AuthTokenInterceptor(tokenService));
        return restTemplate;
    }
}

Interceptor в Spring MVC (Servlet)

Spring MVC имеет HandlerInterceptor для перехвата HTTP запросов на уровне контроллера:

public class RequestTimingInterceptor implements HandlerInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(RequestTimingInterceptor.class);
    private static final String TIMER_KEY = "startTime";
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
            Object handler) throws Exception {
        
        // Выполняется ДО вызова контроллера
        long startTime = System.currentTimeMillis();
        request.setAttribute(TIMER_KEY, startTime);
        
        logger.info("Request started: {} {}", request.getMethod(), request.getRequestURI());
        return true; // true = продолжить обработку, false = остановить
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
            Object handler, ModelAndView modelAndView) throws Exception {
        
        // Выполняется ПОСЛЕ вызова контроллера, но ДО отправки ответа
        long startTime = (Long) request.getAttribute(TIMER_KEY);
        long duration = System.currentTimeMillis() - startTime;
        
        logger.info("Request processed in {}ms", duration);
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
            Object handler, Exception ex) throws Exception {
        
        // Выполняется ПОСЛЕ отправки ответа клиенту
        if (ex != null) {
            logger.error("Request failed with exception", ex);
        }
    }
}

// Регистрация
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestTimingInterceptor())
            .addPathPatterns("/api/**")
            .excludePathPatterns("/api/public/**");
    }
}

Цепочка Interceptors

Несколько Interceptors могут быть применены последовательно:

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())      // 1
    .addInterceptor(new AuthInterceptor())          // 2
    .addInterceptor(new RetryInterceptor())         // 3
    .addNetworkInterceptor(new CompressionInterceptor()) // Сетевой уровень
    .build();

// Порядок выполнения:
// Request: LoggingInterceptor → AuthInterceptor → RetryInterceptor → Network → Server
// Response: Network → RetryInterceptor → AuthInterceptor → LoggingInterceptor → Client

Практический пример: Retry Interceptor

public class RetryInterceptor implements Interceptor {
    private static final int MAX_RETRY = 3;
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        IOException exception = null;
        
        for (int attempt = 0; attempt < MAX_RETRY; attempt++) {
            try {
                return chain.proceed(request);
            } catch (IOException e) {
                exception = e;
                long backoff = 100 * (long) Math.pow(2, attempt);
                System.out.println("Attempt " + (attempt + 1) + " failed, retrying in " + backoff + "ms");
                
                try {
                    Thread.sleep(backoff);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new IOException(ie);
                }
            }
        }
        
        throw exception;
    }
}

Различия между типами Interceptors

OkHttp Interceptor vs Network Interceptor:

// Application Interceptor
.addInterceptor(interceptor)
// - Может модифицировать request/response
// - Видит только финальный ответ (кэш, редиректы уже обработаны)
// - Не повторяется при редиректах

// Network Interceptor
.addNetworkInterceptor(interceptor)
// - Работает ближе к сети
// - Видит все промежуточные запросы (редиректы)
// - Срабатывает для каждого сетевого запроса

Interceptor в Spring WebFlux (Reactive)

@Component
public class LoggingWebFilter implements WebFilter {
    private static final Logger logger = LoggerFactory.getLogger(LoggingWebFilter.class);
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        long startTime = System.currentTimeMillis();
        ServerHttpRequest request = exchange.getRequest();
        
        logger.info("Incoming {} {}", request.getMethod(), request.getPath());
        
        return chain.filter(exchange)
            .doFinally(signalType -> {
                long duration = System.currentTimeMillis() - startTime;
                logger.info("Completed in {}ms", duration);
            });
    }
}

Лучшие практики использования Interceptors

  1. Логирование — записывайте все запросы и ответы
  2. Аутентификация — добавляйте токены в headers
  3. Повторные попытки — обработка временных ошибок
  4. Трансформация ответов — парсинг, кэширование
  5. Error handling — перехват и обработка ошибок
  6. Performance monitoring — измерение времени запросов

Выводы

Interceptor позволяет:

  • Добавлять функциональность без изменения исходного кода
  • Разделять concerns — логирование, аутентификация, трансформация отделены
  • Переиспользовать код — один Interceptor можно применить ко многим запросам
  • Обрабатывать cross-cutting concerns — функциональность, пересекающая несколько слоёв

Это мощный паттерн, особенно при работе с HTTP запросами и сетевыми операциями.