Как паттерн Chain of Responsibility применяется в Spring Boot?

«Как паттерн Chain of Responsibility применяется в Spring Boot?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Spring Boot паттерн Chain of Responsibility реализован в нескольких ключевых механизмах обработки HTTP-запросов:

  1. javax.servlet.Filter: Цепочка фильтров, через которую проходит каждый запрос перед контроллером и после него.
  2. HandlerInterceptor в Spring MVC: Перехватчики для пред-/пост-обработки запросов к контроллерам.
  3. SecurityFilterChain в Spring Security: Цепочка фильтров, отвечающих за аутентификацию, авторизацию и защиту.

Пример реализации цепочки фильтров:

@Component
@Order(1) // Порядок выполнения в цепочке
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain) // Ссылка на следующий элемент цепи
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        System.out.println("Incoming request: " + req.getMethod() + " " + req.getRequestURI());
        long startTime = System.currentTimeMillis();
        // Передача управления следующему фильтру или диспетчеру сервлетов
        chain.doFilter(request, response);
        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Request processed in " + duration + " ms");
    }
}

@Component
@Order(2)
public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String token = req.getHeader("Authorization");
        if (!isValidToken(token)) {
            throw new AccessDeniedException("Invalid token");
        }
        // Только если проверка пройдена, запрос идет дальше
        chain.doFilter(request, response);
    }
    private boolean isValidToken(String token) { /* ... */ }
}

Как это работает:

  • Каждый фильтр (Filter) получает запрос, ответ и ссылку FilterChain на следующий элемент.
  • Фильтр может:
    • Обработать запрос/ответ и передать управление дальше (chain.doFilter(...)).
    • Прервать цепочку, отправив ответ самостоятельно (например, ошибку 401).
  • Порядок выполнения определяется аннотацией @Order или регистрацией в SecurityFilterChain.

Преимущества в Spring Boot: Четкое разделение ответственности (логирование, аутентификация, CORS), легкое добавление или отключение этапов обработки, централизованное управление потоком запросов.