본문 바로가기

Spring

[Spring] Spring URI 매핑 방식의 진화: 초기 Bean 이름 매핑부터 어노테이션 기반까지

 


 

초창기 Spring URI 매핑

1. Java 언어 수준의 제약

  • Spring 2.x 이전은 어노테이션 기반 프로그래밍이 제한적이었습니다.
  • 당시에는 `@Controller`, `@RequestMapping`같은 어노테이션 기반 선언이 없거나 미지원이 많았습니다.
  • 따라서 개발자는 구현체 등록 + 이름 매핑 방식을 사용해서 컨트롤러를 연결했습니다.

 

 

예시 코드

@Component("/example-controller")
public class ExampleController implements Controller {
    
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String method = request.getMethod();
        if ("GET".equalsIgnoreCase(method)) {
            System.out.println("GET 요청 처리");
        }
        return  null;
    }
}

1. 요청

웹 브라우저나 클라이언트에서 `/example-controller`로 요청이 들어옵니다.

GET /example-controller
  • HttpServletRequest 객체에서 Http Method를 확인하여, 조건을 나누었습니다.

 

 

2. DispatcherServlet

Spring은 프론트 컨트롤러인 `DispatcherServlet`이 모든 HTTP 요청을 받아 처리합니다.

DispatcherServlet
     ↓
HandlerMapping
     ↓
Controller

 

 

3. HandlerMapping이 Controller 탐색

`DispatcherServlet`은 등록된 `HandlerMapping`을 이용해 요청 URI에 해당하는 컨트롤러를 찾습니다.

  • `@Component("/example-controller")`처럼 이름을 명시하여 Bean을 등록하면, `BeanNameUrlHandlerMapping(구현체)`은 해당 이름(/example-controller)과 일치하는 URI 요청을 해당 Bean으로 매핑합니다. `DispacherServlet`은 Handler 객체(Controller)에 맞는 `HandlerAdapter`를 통해  `handleRequest()`를 실행합니다. (이름 매핑 방식)

 

 

4. Controller 호출

찾은 컨트롤러의 `handleRequest()` 메서드를 호출합니다

if ("GET".equalsIgnoreCase(method)) {
    System.out.println("GET 요청 처리");
}
return null;
  • `GET` 요청인 경우, 출력이 콘솔에 나오면, Spring이 해당 요청을 `ExampleController`에 잘 연결한 것입니다.

 


 

현재 어노테이션 기반 Spring URI 매핑

과거처럼 `Controller` 인터페이스와 `handleRequest()`를 사용하지 않고, Java 5 이후 도입된 어노테이션을 사용하여 URL과 메서드를 직관적으로 매핑합니다.

 

 

예시 코드

@Controller
@RequestMapping("/example")
public class ExampleController {

    @GetMapping("/hello")
    public String hello() {
        return "helloView";
    }
}

1. 메서드 단위로 매핑 테이블 생성

애플리케이션 실행 시, `@Controller`, `@RequestMapping`이 있는 클래스들을 검사한 후 다음과 같이 매핑을 기억합니다.

GET /example/hello → ExampleController.hello()

 

 

2. 요청

웹 브라우저나 클라이언트에서 `/example/hello`로 GET 요청이 들어옵니다.

GET /example/hello

 

 

3. DispatcherServlet

Spring은 프론트 컨트롤러인 `DispatcherServlet`이 모든 HTTP 요청을 받아 처리합니다.

DispatcherServlet
   ↓
HandlerMapping (인터페이스)
   ↓
RequestMappingHandlerMapping (핸들러 찾음)
   ↓
HandlerMethod 반환

 

4. HandlerMapping을 통해 컨트롤러 메서드(Handler) 찾기

  • `DispatcherServlet`이 요청을 받으면, 등록된 `HandlerMapping(인터페이스)`을 통해 해당 URL과 HTTP method에 매칭되는 `HandlerMethod`를 찾습니다.
    •  `RequestMappingHandlerMapping(구현체)`이  URL("/example/hello"), HTTP method를 보고 매핑된 컨트롤러 메서드(`HandlerMethod`) 클래스를 반환합니다. (컨트롤러 객체 + 메서드 정보)

 

HandlerMethod 예

HandlerMethod {
  bean: ExampleController
  method: hello() // 리플렉션으로 호출될 대상
  ...
}
  • `HandlerMethod`는 실제 컨트롤러 객체와 실행할 메서드 정보를 가지고 있으며, Spring은 리플렉션을 사용하여 이 메서드를 실행합니다. 이는 예전의 `handleRequest()`처럼 단일 진입점이 아니라, 다양한 메서드로 요청을 나눌 수 있게 해줍니다.

 


 

차이점

항목 초창기 Spring 현재 Spring
컨트롤러 선언 방식 `Controller` 인터페이스 구현 `@Controller` 어노테이션 사용
요청 처리 메서드 `handleRequest(HttpServletRequest, HttpServletResponse)` `@GetMapping`, `@PostMapping` 등 어노테이션으로 메서드 직접 매핑
URI 매핑 방식 Bean 이름 기반 매핑 (`@Component("/url")`) `@RequestMapping`, `@GetMapping` 등으로 URL 및 메서드 매핑
HandlerMapping 구현체 `BeanNameUrlHandlerMapping` `RequestMappingHandlerMapping`
핸들러 호출 방식 `Controller`의 `handleRequest()` 메서드 호출 `HandlerMethod`를 통해 리플렉션으로 특정 메서드 실행
요청 구분 방식 `HttpServletRequest.getMethod()`로 직접 분기 `@GetMapping`, `@PostMapping` 등으로 자동 구분
유연성 및 유지보수성 낮음 (URL과 메서드가 하드코딩됨) 높음 (어노테이션으로 명확한 구조 제공)
지원 HTTP 메서드별 처리 수동 if-else 처리 메서드별 어노테이션 사용 (`@GetMapping`, `@PostMapping` 등)
핸들러 정보 표현 컨트롤러 Bean 하나만 반환 `HandlerMethod` 객체에 Bean + Method 정보를 포함하여 반환
코드 가독성 낮음 (로직 분기가 코드 안에 직접 존재) 높음 (매핑이 명시적이고 구조화됨)