Где используется паттерн chain of responsibility в Spring Boot?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# 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 используется:
- Filters (@Component implements Filter)
- Interceptors (HandlerInterceptor)
- Security Filters (Spring Security)
- Exception Handlers (@ExceptionHandler, @ControllerAdvice)
- Custom handlers (собственная реализация)
Этот паттерн позволяет обрабатывать запросы слоями, где каждый слой решает, обработать запрос или передать дальше.