🌐 [Spring] 웹 요청 처리의 핵심, dispatcher-servlet.xml 완벽 분석 (Java Config 전환 포함)

web.xml 분석에 이어, 오늘은 Spring MVC의 실질적인 웹 동작을 정의하는 심장부, dispatcher-servlet.xml 파일에 대해 깊이 있게 파헤쳐 보겠습니다.

web.xml이 웹 서버(Tomcat)에게 "모든 요청을 DispatcherServlet에게 넘겨!"라고 지시했다면, 이 dispatcher-servlet.xml 파일은 DispatcherServlet에게 "요청을 받으면 이렇게 처리해!" 라고 상세한 행동 강령을 알려주는 역할을 합니다. 즉, 컨트롤러를 찾고, 뷰(View)를 연결하고, 어노테이션을 동작시키는 모든 마법이 바로 여기서 시작됩니다.

📝 전체 코드 살펴보기

먼저 분석할 dispatcher-servlet.xml 파일의 전체 코드입니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 1. Component Scan: 컨트롤러를 찾아서 빈으로 등록 -->
    <context:component-scan base-package="com.example.controller" />

    <!-- 2. Enable MVC: 어노테이션 기반 MVC 기능 활성화 -->
    <mvc:annotation-driven />

    <!-- 3. View Resolver: 뷰(JSP) 경로를 완성 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 4. Static Resources: 정적 리소스(CSS, JS, 이미지 등) 처리 위임 -->
    <mvc:default-servlet-handler />
</beans>

 

📝 핵심 설정 분석

이 파일은 크게 4가지의 핵심적인 역할을 수행하도록 구성되어 있습니다.

1. 컴포넌트 스캔 (Component Scan)

<context:component-scan base-package="com.example.controller" />

• 역할: Spring 컨테이너에게 지정된 패키지(com.example.controller)를 스캔하여 특정 어노테이션(@Controller, @Service 등)이 붙은 클래스를 찾아 자동으로 빈(Bean)으로 등록하라고 지시합니다.
• 핵심: 이 설정 덕분에 우리는 컨트롤러 클래스를 만들고 @Controller 어노테이션만 붙이면, Spring이 알아서 해당 객체를 관리해 주므로 XML에 일일이 빈을 등록하는 수고를 덜 수 있습니다.


2. MVC 기능 활성화 (Enable MVC)

<mvc:annotation-driven />

• 역할: 마법의 한 줄입니다. 어노테이션 기반의 현대적인 Spring MVC 기능을 사용하기 위한 필수 설정입니다.
• 주요 기능: 이 태그 하나가 보이지 않는 곳에서 다음과 같은 필수적인 빈들을 등록하고 활성화합니다.
    • @RequestMapping, @GetMapping 등을 처리하는 RequestMappingHandlerMapping.
    • 컨트롤러 메서드를 호출하고 파라미터(@RequestParam 등)를 처리하는 RequestMappingHandlerAdapter.
    • JSON 데이터 변환, 데이터 검증(@Valid) 등 다양한 고급 기능.
• 결론: 이 태그가 없으면 @RequestMapping을 비롯한 대부분의 Spring MVC 어노테이션이 동작하지 않습니다.

3. 뷰 리졸버 (View Resolver)

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

• 역할: 컨트롤러가 반환하는 **논리적인 뷰 이름(Logical View Name)**을 실제 물리적인 뷰 파일 경로로 완성해주는 역할을 합니다.
• 동작 방식:
    1.컨트롤러가 return "home"; 과 같이 문자열을 반환합니다.
    2.ViewResolver는 이 "home"이라는 문자열을 받아, 설정된 prefix와 suffix를 앞뒤에 붙입니다.
    3.최종적으로 /WEB-INF/views/ + home + .jsp  = /WEB-INF/views/home.jsp 라는 실제 파일 경로를 만들어 줍니다.


4. 정적 리소스 처리 (Static Resources)

<mvc:default-servlet-handler />

• 역할: CSS, JavaScript, 이미지 파일 등 동적인 처리가 필요 없는 정적 리소스에 대한 요청을 처리합니다.
• 문제점: web.xml에서 DispatcherServlet의 처리 경로를 /로 지정하면, /css/style.css 같은 정적 파일 요청까지 DispatcherServlet이 가로채게 됩니다. DispatcherServlet은 이 요청을 처리할 컨트롤러를 찾지 못해 404 에러를 발생시킵니다.
• 해결책: 이 태그는 "만약 들어온 요청을 처리할 컨트롤러 매핑이 없다면, 그 요청을 Spring이 처리하지 말고 원래 웹 서버(Tomcat)의 기본 서블릿에게 넘겨라" 라고 설정합니다. 그러면 웹 서버가 정적 파일을 올바르게 찾아 클라이언트에게 제공할 수 있습니다.


📝 
더 나은 코드를 향하여: Java 기반 설정으로의 완전한 전환

XML 설정은 직관적이지만, 현대적인 Spring 개발에서는 타입 안정성(type-safe)과 리팩토링 용이성이 뛰어난 **Java 기반 설정(Java-based Configuration)**을 사용하는 것이 표준입니다.

아래와 같이 web.xml과 dispatcher-servlet.xml을 모두 제거하고 순수 Java 코드로 프로젝트를 설정할 수 있습니다

1단계: dispatcher-servlet.xml을 대체할 WebConfig 클래스 생성

먼저, dispatcher-servlet.xml의 모든 기능을 수행하는 Java 설정 클래스를 만듭니다.

// WebConfig.java
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc // <mvc:annotation-driven /> 역할
@ComponentScan(basePackages = "com.example.controller") // <context:component-scan /> 역할
public class WebConfig implements WebMvcConfigurer {

    // InternalResourceViewResolver 빈 등록
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    // <mvc:default-servlet-handler /> 역할
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

 

2단계: web.xml을 대체할 MyWebAppInitializer 클래스 생성

다음으로, web.xml의 역할을 수행하며 위에서 만든 WebConfig를 로드하는 초기화 클래스를 만듭니다. 이 방법을 사용하면 web.xml 파일을 프로젝트에서 완전히 삭제할 수 있습니다.

//MyWebAppInitializer.java
package com.example.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // Root ApplicationContext에 대한 설정 (Service, Repository 등). 현재는 없으므로 null.
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    // DispatcherServlet의 Servlet ApplicationContext에 대한 설정 (Controller, ViewResolver 등)
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{WebConfig.class};
    }

    // DispatcherServlet이 처리할 요청 경로 지정
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 인코딩 필터 설정
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        return new Filter[]{encodingFilter};
    }
}

 

🎯 마무리

오늘은 Spring MVC의 웹 요청 처리 로직을 담당하는 dispatcher-servlet.xml을 분석하고, 이를 현대적인 Java 설정으로 전환하는 방법까지 알아보았습니다.

요약:
    1.component-scan: @Controller를 찾아 빈으로 등록합니다.
    2.annotation-driven: @RequestMapping 등 MVC 어노테이션을 활성화합니다.
    3.ViewResolver: 컨트롤러가 반환한 뷰 이름을 실제 JSP 파일 경로로 완성합니다.
    4.default-servlet-handler: CSS, JS 같은 정적 리소스 요청을 처리합니다.

비록 Spring Boot가 많은 부분을 자동화해주지만, 그 내부에서 어떤 일들이 일어나는지 이해하는 것은 문제 해결 능력과 애플리케이션 설계 능력을 한 단계 끌어올리는 데 큰 도움이 됩니다. 이 글이 여러분의 Spring 학습에 도움이 되었기를 바랍니다

 

 

+ Recent posts