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

Где используется паттерн chain of responsibility в Spring Boot?

2.0 Middle🔥 111 комментариев
#Spring Framework

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

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

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

# Chain of Responsibility в Spring Boot

Паттерн Chain of Responsibility активно используется в Spring Boot для обработки запросов в виде цепочки обработчиков.

Что это за паттерн?

Chain of Responsibility — это поведенческий паттерн, где запрос передаётся по цепочке обработчиков, и каждый решает, обработать его или передать дальше.

Запрос → [Handler 1] → [Handler 2] → [Handler 3] → Response

1. Spring Filters — Основное использование

Структура Filter

// Фильтр — это звено в цепи
@Component
public class LoggingFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, 
                        ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        System.out.println("[Filter] Before request");
        
        // Передаём запрос дальше по цепи
        chain.doFilter(request, response);
        
        System.out.println("[Filter] After response");
    }
}

@Component
public class AuthenticationFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, 
                        ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String token = httpRequest.getHeader("Authorization");
        
        if (token != null && isValidToken(token)) {
            System.out.println("[AuthFilter] Token valid");
            chain.doFilter(request, response); // Передаём дальше
        } else {
            System.out.println("[AuthFilter] Token invalid");
            // Не передаём дальше — цепь обрывается
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        }
    }
    
    private boolean isValidToken(String token) {
        return token.startsWith("Bearer ");
    }
}

FilterChain — цепочка

// FilterChain — это реализация паттерна
public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response) 
        throws IOException, ServletException;
}

// Spring создаёт цепь из всех Filter бинов
// Порядок:
// 1. LoggingFilter
// 2. AuthenticationFilter
// 3. Контроллер
// 4. AuthenticationFilter (после обработки)
// 5. LoggingFilter (после обработки)

Пример выполнения

HTTP Request
     ↓
[LoggingFilter.doFilter]
  "[Filter] Before request"
     ↓
[AuthenticationFilter.doFilter]
  "[AuthFilter] Token valid"
  chain.doFilter(...) → передаёт дальше
     ↓
[DispatcherServlet]
     ↓
[Controller]
     ↓
[AuthenticationFilter.doFilter] (продолжение после chain.doFilter)
     ↓
[LoggingFilter.doFilter] (продолжение после chain.doFilter)
  "[Filter] After response"
     ↓
HTTP Response

2. Spring Security Filters

Spring Security использует Chain of Responsibility для обработки безопасности:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // Цепочка фильтров безопасности!
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
                .httpBasic()
            .and()
                .csrf().disable();
    }
}

// Внутри Spring Security создаётся цепь фильтров:
// SecurityContextPersistenceFilter (сохранение контекста)
// → HeaderWriterFilter (добавление заголовков)
// → ExceptionTranslationFilter (обработка исключений)
// → FilterSecurityInterceptor (проверка доступа)

3. Interceptors в Spring MVC

// Перехватчик — еще одна реализация Chain of Responsibility
@Component
public class RequestTimingInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                            HttpServletResponse response, 
                            Object handler) throws Exception {
        request.setAttribute("startTime", System.currentTimeMillis());
        return true; // true — продолжить цепь, false — остановить
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                          HttpServletResponse response, 
                          Object handler, 
                          ModelAndView modelAndView) throws Exception {
        long startTime = (long) request.getAttribute("startTime");
        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Request took " + duration + "ms");
    }
}

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Цепь перехватчиков
        registry.addInterceptor(new RequestTimingInterceptor());
        registry.addInterceptor(new AuthorizationInterceptor());
        registry.addInterceptor(new CacheInterceptor());
    }
}

// Порядок выполнения:
// preHandle():   1 → 2 → 3
// postHandle(): 3 → 2 → 1 (обратный порядок)

4. Стандартная цепь фильтров в Spring Boot

// Вот как это выглядит по умолчанию:

public class FilterChainProxy {
    private List<SecurityFilterChain> filterChains;
    
    public void doFilter(ServletRequest request, 
                        ServletResponse response, 
                        FilterChain chain) throws ServletException, IOException {
        
        // Проходим по цепи фильтров
        for (SecurityFilterChain filterChain : filterChains) {
            if (filterChain.matches(request)) {
                // Нашли подходящую цепь
                filterChain.doFilter(request, response, chain);
                return;
            }
        }
        
        // Если ни один фильтр не обработал — передаём дальше
        chain.doFilter(request, response);
    }
}

5. Практический пример: Кастомная цепь

// Интерфейс для обработчика
public interface RequestHandler {
    void handle(Request request, Response response);
    void setNext(RequestHandler next);
}

// Абстрактный обработчик
public abstract class BaseHandler implements RequestHandler {
    protected RequestHandler next;
    
    @Override
    public void setNext(RequestHandler next) {
        this.next = next;
    }
    
    protected void passToNext(Request request, Response response) {
        if (next != null) {
            next.handle(request, response);
        }
    }
}

// Валидация запроса
@Component
public class ValidationHandler extends BaseHandler {
    
    @Override
    public void handle(Request request, Response response) {
        if (request.getBody() == null || request.getBody().isEmpty()) {
            response.setStatus(400);
            response.setBody("Invalid request");
            return; // Цепь обрывается
        }
        System.out.println("[ValidationHandler] OK");
        passToNext(request, response);
    }
}

// Аутентификация
@Component
public class AuthenticationHandler extends BaseHandler {
    
    @Override
    public void handle(Request request, Response response) {
        String token = request.getHeader("Authorization");
        if (token == null || !validateToken(token)) {
            response.setStatus(401);
            response.setBody("Unauthorized");
            return; // Цепь обрывается
        }
        System.out.println("[AuthenticationHandler] OK");
        passToNext(request, response);
    }
    
    private boolean validateToken(String token) {
        return token.startsWith("Bearer ");
    }
}

// Обработка бизнес-логики
@Component
public class BusinessLogicHandler extends BaseHandler {
    
    @Override
    public void handle(Request request, Response response) {
        // Выполняем основную работу
        System.out.println("[BusinessLogicHandler] Processing");
        response.setStatus(200);
        response.setBody("Success");
        passToNext(request, response);
    }
}

// Конфигурация цепи
@Configuration
public class HandlerChainConfig {
    
    @Bean
    public RequestHandler handlerChain(
            ValidationHandler validation,
            AuthenticationHandler authentication,
            BusinessLogicHandler business) {
        
        // Строим цепь: Валидация → Аутентификация → Бизнес-логика
        validation.setNext(authentication);
        authentication.setNext(business);
        
        return validation; // Возвращаем начало цепи
    }
}

// Использование
@RestController
public class RequestController {
    
    @Autowired
    private RequestHandler handler;
    
    @PostMapping("/process")
    public void processRequest(@RequestBody String body) {
        Request req = new Request(body);
        Response res = new Response();
        handler.handle(req, res);
    }
}

// Выполнение:
// [ValidationHandler] OK
// [AuthenticationHandler] OK
// [BusinessLogicHandler] Processing

Где ещё используется Chain of Responsibility

1. Exception Handling

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<String> handleNPE(NullPointerException e) {
        // Обработка NullPointerException
        return ResponseEntity.status(500).body("NPE occurred");
    }
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIAE(IllegalArgumentException e) {
        // Обработка IllegalArgumentException
        return ResponseEntity.status(400).body("Invalid argument");
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneral(Exception e) {
        // Обработка всех остальных исключений
        return ResponseEntity.status(500).body("Internal error");
    }
}

2. Request/Response Logging

public class RequestResponseLoggingFilter extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   FilterChain filterChain) 
        throws ServletException, IOException {
        
        // Логирование запроса
        logger.info("Method: " + request.getMethod());
        logger.info("URI: " + request.getRequestURI());
        
        // Продолжаем цепь
        filterChain.doFilter(request, response);
        
        // Логирование ответа
        logger.info("Status: " + response.getStatus());
    }
}

Преимущества Chain of Responsibility в Spring

Разделение ответственности — каждый handler отвечает за одно

Гибкость — легко добавить/удалить/переупорядочить обработчики

Переиспользование — фильтры можно применять к разным маршрутам

Декларативность — аннотации (@Filter, @Component) автоматически регистрируют в цепь

Комбинируемость — можно комбинировать фильтры и перехватчики

Вывод

Chain of Responsibility в Spring Boot используется:

  1. Filters (@Component implements Filter)
  2. Interceptors (HandlerInterceptor)
  3. Security Filters (Spring Security)
  4. Exception Handlers (@ExceptionHandler, @ControllerAdvice)
  5. Custom handlers (собственная реализация)

Этот паттерн позволяет обрабатывать запросы слоями, где каждый слой решает, обработать запрос или передать дальше.