Spring Web MVC의 Dispatcher Servlet의 동작 원리에 대해서 간단히 설명
DispatcherServlet은 Front Controller 패턴을 기반으로 동작하는 Spring MVC의 핵심 서블릿입니다. 요청을 받아서 적절한 컨트롤러로 전달하고, 이후의 응답 처리를 담당합니다.
DispatcherServlet의 동작 과정
1. 클라이언트 요청
• 사용자가 URL을 입력하면 요청이 들어옵니다.
2. DispatcherServlet이 요청을 받음
• 요청이 DispatcherServlet에 의해 가로채집니다. (Spring Boot에서는 기본적으로 /* 경로에 매핑됨)
3. HandlerMapping을 통해 컨트롤러 검색
• 요청 URL에 맞는 적절한 컨트롤러(@Controller)를 찾기 위해 여러 HandlerMapping이 실행됩니다.
4. HandlerAdapter 실행
• 컨트롤러를 실행할 수 있도록 HandlerAdapter가 적절한 방법을 찾아서 호출합니다.
5. Controller의 메서드 실행 및 결과 반환
• 컨트롤러(@Controller 또는 @RestController)의 메서드가 실행되고 ModelAndView 또는 JSON 데이터가 반환됩니다.
6. ViewResolver를 통해 뷰 선택
• 반환된 View 객체를 ViewResolver가 해석하여 알맞은 뷰를 찾습니다. (.jsp, .html, Thymeleaf 등)
7. 응답 반환
• 최종적으로 클라이언트에게 HTML 또는 JSON 등의 형태로 응답이 전달됩니다.
핵심 개념
• DispatcherServlet은 프론트 컨트롤러(Front Controller)로 동작하며, 모든 요청을 중앙에서 관리합니다.
• HandlerMapping과 HandlerAdapter를 이용하여 적절한 컨트롤러를 찾고 실행합니다.
• ViewResolver를 통해 응답을 생성하고 반환합니다.
프론트 컨트롤러 패턴이란 무엇?
프론트 컨트롤러(Front Controller) 패턴은 웹 애플리케이션에서 모든 요청을 하나의 컨트롤러에서 받아 처리하는 방식을 의미합니다.
특징
1. 모든 요청을 하나의 진입점(DispatcherServlet)에서 관리
2. 요청을 적절한 컨트롤러로 위임하여 처리
3. 코드의 일관성 유지 및 중복 제거 가능
4. 보안, 로깅, 인증 등의 기능을 중앙 집중적으로 처리 가능
Spring MVC에서는 DispatcherServlet이 프론트 컨트롤러 역할을 수행합니다.
Servlet Filter와 Spring Interceptor의 차이는 무엇?

Filter 예제
@WebFilter("/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter 실행됨");
chain.doFilter(request, response);
}
}
Interceptor 예제
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor 실행됨");
return true;
}
}
Spring에서 CORS 에러를 해결하기 위한 방법을 설명
CORS (Cross-Origin Resource Sharing) 문제는 다른 도메인에서 요청할 때 브라우저에서 차단하는 문제입니다.
Servlet Filter를 사용하여 커스텀한 Cors 설정하거나,
WebMvcConfiguer를 구현한 Configuration 클래스를 만들어서 addCorsMappings()를 재정의할 수도 있고,
마지막으로 Spring Security에서 CorsConfigurationSource를 Bean으로 등록하고 config에 추가해줌으로써 해결할 수 있습니다.
Controller 클래스에 @Crossorigin 어노테이션을 통해 해결할 수 있습니다.
해결 방법
1. Controller에서 @CrossOrigin 사용
@RestController
@CrossOrigin(origins = "https://example.com")
public class MyController {
@GetMapping("/data")
public String getData() {
return "Hello!";
}
}
2. Global 설정 (WebMvcConfigurer)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
}
Bean/Component 어노테이션에 대해서 설명해주시고, 둘의 차이점에 대해 설명
두 어노테이션 모두 IoC 컨테이너에 Bean을 등록하기 위해 사용합니다
@Component : 개발자가 작성한 class를 기반으로 실행시점에 인스턴스 객체를 1회(싱글톤) 생성합니다
@Controller, @Service, @Repository 는 모두 @Component 이며 실행시점에 자동으로 의존성을 주입합니다
@Bean : 개발자가 작성한 method를 기반으로 메서드에서 반환하는 객체를 인스턴스 객체로 1회(싱글톤) 생성합니다

POJO란 무엇인가요? Spring Framework에서 POJO는 무엇이 될 수 있을까요?
POJO(Plain Old Java Object) 는 특정 프레임워크에 종속되지 않는 순수한 Java 객체를 의미합니다.
POJO는 프레임워크 인터페이스, 클래스를 구현하거나 확장하지 않은 단순한 클래스로 Java에서 제공하는 API 외에 종속되지 않습니다.
특정 환경에 종속되지 않아 코드가 간결하고 테스트 자동화에 유리합니다.
스프링에서는 도메인과 비즈니스 로직을 수행하는 대상이 POJO대상이 될 수 있습니다.
Spring에서 POJO의 역할
• Spring의 @Component, @Service, @Repository, @Controller로 선언된 클래스들은 POJO입니다.
• Spring이 객체 생명 주기 관리를 해주지만, POJO의 본질은 유지됩니다.
Spring Web MVC에서 요청 마다 Thread가 생성되어 Controller를 통해 요청을 수행할텐데, 어떻게 1개의 Controller만 생성될 수 있을까요?
Spring의 컨트롤러(@Controller)는 싱글톤(Bean 스코프 기본값이 Singleton)으로 관리되기 때문입니다.
• 요청이 올 때마다 새로운 컨트롤러 객체를 생성하는 것이 아니라, 하나의 인스턴스를 공유하면서 멀티스레드 환경에서 동작합니다.
• 공유되는 데이터를 @RequestScope, ThreadLocal 등을 이용해 관리할 수 있습니다.
@Controller 어노테이션을 타고 들어가보면 @Component라는 어노테이션이 붙어 있습니다. 따라서 컨트롤러는 IoC컨테이너에 등록되어 Spring bean으로 관리됩니다.
Spring의 빈 생성 전략의 기본은 싱글턴입니다. IoC컨테이너에 Controller Bean은 싱글턴 전략에 의해 1개만 존재하고 Application이 Init 되는 시점에 초기화됩니다.
그리고 실제 사용되는 시점에 의존성 주입을 통해서 사용됩니다. 요청시마다 새로 Bean을 생성해서 사용하는 것이 아닌 이미 생성되어있는 Bean을 가져다 쓰게됨으로써 여러개의 Thread에서 Contoller를 사용해도 1개의 동일한 컨트롤러인 것입니다.
만약 요청이 올때마다 새로운 컨트롤러가 생기길 바란다면 Bean scope를 Singleton 이 아닌, request 등으로 설정하면 요청이 들어올 때 혹은 지정한 전략마다 새로운 컨트롤러 Bean이 생기도록 할 수 있습니다.
Spring WEB MVC의 근간에는 Java Servlet 이 있는데요. Spring 은 Servlet을 어떻게 구성해서 이를 구현했을까요?
Servlet은 Java로 웹페이지를 구성할 때 동적으로 웹페이지를 구성해주는 자바 클래스 입니다.
Spring에서도 이 Servlet을 사용하고 있지만 특성이 조금 다릅니다. 기본적으로 Java의 Servlet은 하나의 Request에 대해서 하나의 Servlet을 생성합니다. 이 방법은 간단하고 직관적이지만 Servlet이 많이 생성되면 관리하기 힘들어지는 단점이 있습니다.
반면 Spring의 경우에는 DispatcherServlet이라는 FrontController 패턴을 사용해서 중앙에서 하나의 Servlet이 요청을 받아서 HandlerMapping을 통해 그에 맞는 컨트롤러로 분배하는 방식을 사용합니다.
이렇게 할 경우 하나의 객체에서 모든 요청을 먼저 처리하기 때문에 재사용성 및 유연한 매핑, 인터셉터의 사용, 관리의 용이성 등이 있겠습니다.
• DispatcherServlet이 서블릿을 확장하여 MVC 구조를 지원
• Filter, Listener 등을 활용하여 요청을 전처리/후처리
• HttpServletRequest, HttpServletResponse를 사용해 직접 HTTP 처리 가능
Filter는 Servlet의 스펙이고, Interceptor는 Spring MVC의 스펙입니다. Spring Application에서 Filter와 Interceptor를 통해 예외를 처리할 경우 어떻게 해야 할까요?
1. Filter
2. Interceptor
Spring Application을 구동할 때 메서드를 실행시키는 방법에 대해 설명
CommandLineRunner, ApplicationRunner를 구현한 클래스를 만들어서 실행시키는 2가지 방법이 있습니다.
또한 Spring의 ApplicationEvent를 사용한 방법,
@Postconstruct를 사용한 방법,
InitializingBean 인터페이스를 구현하는 방법,
@Bean의 initMethod를 사용한 방법이 있습니다.
의존성과 설정값을 생성자 인자로 주입해야 하는 이유에 대해 설명
• 불변성 유지
• 테스트 용이성 증가
• 순환 참조 방지(순환 참조란 : 두 개 이상의 빈(Bean) 또는 객체가 서로를 의존하면서 무한 루프를 발생시키는 문제를 의미)
• 의존성 명확화
모든 의존성을 생성자를 통해 주입하면, 인스턴스 생성 시 즉시 어떠한 동작을 실행할 수 있습니다.
또한 추가적인 설정은 필요하지 않으며,
뜻하지 않게 의존성과 설정값을 빠뜨리는 일이 발생하지 않고
테스트에도 용이합니다.