Spring Boot (+ RESTful)

Spring Boot - @EnableAutoConfiguration의 동작 원리 / @ComponentScan의 동작 원리

wy-family 2024. 12. 13. 13:16

@SpringBootApplication 어노테이션은

- @SpringBootConfiguration

- @EnableAutoConfiguration

- @ComponentScan

을 결합한 것이라고 했다.

 

이제 EnableAutoConfiguration을 알아보자.

- @SpringBootConfiguration 의 경우에는 Web 하고는 관련이 없었다.

Spring Web MVC 에서 중요한 건 FrontController, HandlerMapping, ViewResolver 등

즉, Web에서 사용할 수 있는 미리 만들어져 있는 클래스들을 메모리(Spring Container)에 올려야 한다.

그런 애들을 어떻게 올리냐, @EnableAutoConfiguration 을 통해서 올린다. 자동으로 환경 구성을 할 수 있다는 어노테이션이다.

 

어노테이션은 미리 뭔가를 하기 위해서 전처리를 하는것이라고 했다. 그러니까 미리 메모리에 필요한 걸 올려놓는 것.

- @EnableAutoConfiguration 라는 어노테이션을 해석하는 클래스가 있다.

AutoConfigurationImportSelector 라는 클래스가 해석을 한다.

이 클래스는 '모든 자동 구성 클래스'를 나열하는 클래스 경로에서 spring.factories 파일을 읽는다.

어떤 것들을 메모리에 올려야 하는지 목록들, 설명서가 있는데 그게 spring.factories 파일이 있다. 해당 파일을 보고 일을 하는 것. 

 

 

정리를 해보면, @EnableAutoConfiguration 이 붙어있으면,

AutoConfigurationImportSelector 이 클래스가 자동 구성 파일인 spring.factories에 설정되어 있는 클래스들을 메모리에 자동으로 올린다는 것.

 

Spring Boot 최근 버전에서는 자동 구성 클래스를 spring.factories 말고 

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 에 나열한다.

더블클릭해서 들어가보면 엄청 많은 자동 구성 클래스 목록들이 있다.

그것들을 모두 메모리에 로딩을 한다는 것.

자동 구성 클래스 목록들 중에서 가장 중요한 몇가지 것들이 있다.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\

org.springframework.boot.autoconfigure.web.servlet.HttpMessageConvertersAutoConfiguration,\

org.springframework.boot.autoconfigure.web.reactive.WebClientAutoConfiguration,\

org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration

 

WebMvcAutoConfiguration

- Spring MVC 를 자동으로 구성한다

- DispatcherServlet(FrontController), RequestMapping(HandlerMapping) 및 기타 MVC 관련 Bean(ViewResolver)를 등록한다

- 클라이언트가 8080 포트로 요청을 하면 FrontController가 요청을 받는다

- 그 다음에, FrontController가 어떤 요청인지에 따라 어떤 POJO를 실행되야 될 것인지를 알아야 되기 때문에 HandlerMapping한테 요청을 한다.

 - 그러면 HandlerMapping이 그 요청과 POJO를 연결해주면 다시 FrontController한테 요청이 가고 FrontController가 POJO한테 요청을 한다.

- 어쨌든, 이렇게 중요한 FrontController, HandlerMapping, ViewResolver가 메모리에 올라가 있어야 하기 때문에 WebMvcAutoConfiguration 어노테이션이 필요한 것.

 

HttpMessageConvertersAutoConfiguration

- JSON, XML 및 기타 형식을 처리하는 기본 HttpMessageConverter Bean을 등록한다

- JSON, XML 및 기타 형식으로 응답을 하기 위해서는 객체를 변환시켜주는 Converter 가 메모리에 올라가 있어야 해서 @HttpMessageConvertersAutoConfiguration 에 의해 메모리에 등록이 된다.

 

WebClientAutoConfiguration

- HTTP 요청을 만들기 위해 'WebClient'를 구성한다

- HTTP 요청을 받기 위해서 내부적으로 HTTP Client를 구성하는 auto configuration이다.

 

EmbeddedWebServerFactoryCustomizerAutoConfiguration

- Tomcat과 같은 임베디드 서블릿 컨테이너를 구성한다.


@EnableAutoConfiguration과 @Configuration의 차이

  • @Configuration:
    • 개발자가 명시적으로 설정을 정의.
    • Java 기반 설정 파일에 사용.
  • @EnableAutoConfiguration:
    • 애플리케이션 실행 시 Spring Boot가 자동으로 설정을 추가.
    • 의존성(JAR 파일)에 따라 필요한 설정을 조건부로 활성화.

@EnableAutoConfiguration 어노테이션에 대해 자세히 설명하겠습니다. 내용을 구조화하고 구체적으로 보완하여 더 명확하게 전달하겠습니다.


1. @EnableAutoConfiguration의 역할

  • **@EnableAutoConfiguration**은 Spring Boot 애플리케이션에서 자동으로 환경을 구성하기 위한 어노테이션입니다.
  • 개발자가 개별적으로 설정하지 않아도 Spring Boot가 필요한 설정과 Bean을 Spring Container에 등록합니다.
  • 특히, 웹 애플리케이션에서는 FrontController(DispatcherServlet), HandlerMapping, ViewResolver 등과 같은 중요한 Web MVC 구성 요소를 자동으로 메모리에 올립니다.

2. @EnableAutoConfiguration의 동작 원리

1) AutoConfigurationImportSelector 클래스

  • @EnableAutoConfiguration은 내부적으로 **AutoConfigurationImportSelector**라는 클래스를 사용해 자동 구성 클래스를 처리합니다.
  • 이 클래스는 Spring Boot 애플리케이션이 시작될 때 자동 구성 클래스 목록을 읽어 필요한 Bean들을 Spring Container에 등록합니다.

2) spring.factories 또는 AutoConfiguration.imports 파일

  • 자동 구성 클래스 목록은 Spring Boot의 META-INF/spring.factories 또는 AutoConfiguration.imports 파일에 정의되어 있습니다.
    • spring.factories 파일은 이전 버전(Spring Boot 2.x)에서 사용되었으며, 최신 버전(Spring Boot 3.x)에서는 **AutoConfiguration.imports**로 대체되었습니다.

3. 주요 자동 구성 클래스와 역할

1) WebMvcAutoConfiguration

  • Spring Web MVC와 관련된 핵심 구성 요소를 자동으로 등록합니다.
  • 등록되는 주요 Bean:
    • DispatcherServlet (FrontController):
      • 모든 HTTP 요청을 처리하는 중앙 컨트롤러입니다.
      • 클라이언트가 요청을 보낼 때 가장 먼저 실행됩니다.
    • HandlerMapping:
      • 요청 URL을 처리할 POJO(Plain Old Java Object)와 연결합니다.
      • FrontController가 요청을 적절한 Handler로 라우팅할 수 있도록 지원합니다.
    • ViewResolver:
      • 컨트롤러가 반환한 데이터를 기반으로 사용자에게 보일 View(HTML, JSON 등)를 생성합니다.
  • 작동 흐름:
    1. 클라이언트가 HTTP 요청을 보냅니다.
    2. DispatcherServlet이 요청을 받습니다.
    3. HandlerMapping이 요청과 관련된 POJO를 찾습니다.
    4. DispatcherServlet이 POJO를 실행하고 결과를 View로 변환합니다.

2) HttpMessageConvertersAutoConfiguration

  • JSON, XML 등 다양한 데이터 형식을 처리하기 위한 HttpMessageConverter를 자동 등록합니다.
  • 주요 역할:
    • 컨트롤러에서 반환된 객체를 JSON 또는 XML 형식으로 변환하여 클라이언트에게 응답.
    • 예: Jackson을 사용한 JSON 변환.

3) WebClientAutoConfiguration

  • **WebClient**는 비동기 HTTP 요청을 위한 클라이언트이며, 이를 구성하는 자동 설정을 제공합니다.
  • 주요 역할:
    • Spring WebFlux에서 사용되는 HTTP 요청 클라이언트를 구성합니다.
    • REST API 호출 및 비동기 HTTP 요청을 처리합니다.

4) EmbeddedWebServerFactoryCustomizerAutoConfiguration

  • Tomcat, Jetty, Undertow와 같은 내장 웹 서버를 자동으로 구성합니다.
  • 주요 역할:
    • 서버 포트, 컨텍스트 경로, SSL 설정 등 임베디드 웹 서버의 기본 설정을 제공합니다.
    • 예: application.properties에서 포트를 변경:
      properties
      Copy code
      server.port=8081

4. @EnableAutoConfiguration이 중요한 이유

1) 자동 구성으로 개발 생산성 향상

  • 개발자가 직접 DispatcherServlet, HandlerMapping, DataSource 등을 설정할 필요 없이, 필요한 Bean이 자동으로 등록됩니다.
  • 기본 설정이 제공되므로, 필요한 경우에만 커스터마이징 하면 됩니다.

2) 유연한 조건부 로딩

  • Spring Boot는 특정 조건에서만 자동 구성 클래스를 활성화합니다.
  • 주요 조건:
    • @ConditionalOnClass: 클래스패스에 특정 클래스가 존재할 경우 활성화.
    • @ConditionalOnMissingBean: 동일한 Bean이 없는 경우에만 활성화.

@ComponentScan

- 간단하게 설명하면,

주로 **의존성 주입(Dependency Injection)**을 위해

**@Component, @Service, @Repository, @Controller**와 같은 어노테이션이 붙은 클래스를 탐지하고, Spring Container에 등록합니다.

 

 

- controller 패키지가 스캔이 된다고 보면 된다. @Controller 가 붙어 있는 HomeController가 메모리에 올라가게 된다. 객체가 생성되게 된다. @GetMapping("/home") 이라는 어노테이션이 붙어있는데, 이 어노테이션은 HandlerMapping 같은 것이 해석한다. HandlerMapping 은 @GetMapping 같은 어노테이션이 붙어있으면, "아, /home 이라는 요청이 오면 HomeController 라는 클래스가 처리하면 되겠구나" 라고 실제로 실행을 하기 전에 전처리로 해석을 미리 해놓게 되는 것.

- controller 패키지 내에 여러가지 @Controller가 있을건데, 각각의 Controller에는 @GetMapping 처럼 어떤 어노테이션이 있을것인데, HandlerMapping은 미리 어떤 요청이  오면 어떤 클래스로 처리하면 되는지에 대한 목록을 전부 미리 가지고 있게 된다.

- 그 목록을 DispatchServlet (FrontController) 한테 주는 것이다.

그러니까 요청 순서는

- 클라이언트가 8080으로 요청이 오면

- 가장 먼저 DispatchServlet (FrontController) 가 요청을 받고

- 그 다음에 이 요청을 HandlerMapping한테 가고

- HandlerMapping이 POJO가 메모리 데이터에 다 올라가 있으니까 ( 어떤 클래스로 처리하면 되는지에 대한 목록을 가지고 있으니까) 찾아가지고, 어떤 요청이 오면 어떤 POJO가 실행할 것인지에 대해서 그 결과를 DispatchServlet (FrontController) 한테 줄 것이고

- DispatchServlet (FrontController)  는 누가 처리하는지 아니까 특정 POJO한테 일을 시킬 것이다.

- 그러면 그 POJO는 service repository 등 쭉쭉 뭔가 일을 처리할 것. 그래서 그 일 처리 후에 나온 결과를 DispatchServlet (FrontController) 한테 넘겨주게 된다.

- 그러면 DispatchServlet (FrontController) 가 View로 포워딩(ViewResolver가 도와주는 일)해서 응답을 하던가, 아니면 다른 다른 Controller 한테 redirect 하던가 하는 식의 그런 절차로 MVC가 동작을 하는 것.

 

어쨌든, 이런식으로 서비스를 할 수 있도록 메모리 구성을 해야 되기 떄문에 그 구성을 개발자가 직접 하는게 아니라 Spring Boot는 AutoConfiguration 자동 설정 기능이 있기 때문에 손쉽게 된다는 것.

그 자동 설정 기능이 @SpringBootApplication 에 다 포함되어 있다는 것이다.

 

그래서 @ComponentScan 에 의해서 @Controller 가 붙어있는 클래스들은 모두 객체 생성이 자동이 이루어질 것이다. new Constructor() 가 진행된다는 것이다. 그걸 확인해보기 위해서, controller 패키지에 있는 HomeController 에 Constructor에도 sout 를 집어넣어주면, 확인할 수 있다.

 

 

참고로, Constructor() 정의가 안 되어 있어도 클래스는 자체적으로 생성자 메소드가 있다는 건, 기억하고 있겠지? 나 자신에게 하는 말.

 

@ComponentScan 이라는 어노테이션이 있으면 ClassPathBeanDefinitionScanner 라는 클래스가 내부적으로 동작이 이루어져서 @Component, @Service, @Repository, @Controller 주석을 감지하고 이러한 클래스를 ApplicationContext (Spring Container) 에 Bean 으로 등록한다. (객체를 생성하고 메모리에 올려놓는)


당신이 필기한 내용을 기반으로 **@ComponentScan**에 대해 더 체계적으로 정리하고 설명해보겠습니다.


1. @ComponentScan의 역할

  • **@ComponentScan**은 Spring Framework에서 클래스를 자동으로 탐지하여 Spring Container에 Bean으로 등록하는 어노테이션입니다.
  • **의존성 주입(Dependency Injection)**을 위해 다음과 같은 어노테이션이 붙은 클래스를 탐지합니다:
    • @Component
    • @Service
    • @Repository
    • @Controller
  • **Spring Container(ApplicationContext)**에 Bean을 등록하는 과정을 자동화하여, 개발자가 일일이 Bean을 등록하지 않아도 되도록 돕습니다.

2. 주요 동작 과정

1) @ComponentScan이 스캔하는 대상

  • Spring Boot 애플리케이션에서는 @SpringBootApplication 내부에 포함된 **@ComponentScan**이 활성화됩니다.
  • 기본적으로 @SpringBootApplication이 위치한 클래스의 패키지와 하위 패키지를 스캔합니다.
  • 이때, @Component, @Service, @Repository, @Controller와 같은 어노테이션이 붙은 클래스가 스캔 대상이 됩니다.

2) Controller 클래스와 HandlerMapping의 상호작용

  • @Controller가 붙은 클래스(예: HomeController)를 탐지하여 Spring Container에 등록합니다.
  • @GetMapping, @PostMapping 등 HTTP 요청 매핑 관련 어노테이션도 함께 탐지됩니다.
  • HandlerMapping이 이 매핑 정보를 읽고, 어떤 URL 요청이 어떤 Controller 메서드로 처리되어야 하는지를 미리 매핑 목록으로 정리합니다.

3. Spring MVC 요청 처리 흐름

요청 흐름

  1. 클라이언트 요청:
    • 사용자가 http://localhost:8080/home으로 요청을 보냅니다.
  2. DispatcherServlet (FrontController):
    • Spring의 중앙 요청 처리 역할을 합니다.
    • 모든 HTTP 요청을 가장 먼저 받습니다.
  3. HandlerMapping:
    • @ComponentScan을 통해 등록된 Controller와 요청 매핑 정보를 조회합니다.
    • 요청된 URL("/home")에 해당하는 Controller 메서드(예: HomeController.home())를 찾아 DispatcherServlet에 전달합니다.
  4. Controller 처리:
    • HandlerMapping이 전달한 정보에 따라 DispatcherServlet이 요청을 해당 Controller의 메서드로 전달합니다.
    • Controller는 요청을 처리하고, Service나 Repository를 호출하여 필요한 작업을 수행합니다.
  5. 응답 처리:
    • Controller는 결과 데이터를 DispatcherServlet에 반환합니다.
    • DispatcherServlet은 결과를 ViewResolver를 통해 적절한 뷰로 변환(HTML, JSON 등)하거나, 다른 Controller로 리다이렉트합니다.
    • 최종적으로 클라이언트에게 응답이 전달됩니다.

4. 메모리와 객체 생성

  • @ComponentScan은 ClassPathBeanDefinitionScanner를 통해 클래스 경로를 스캔하여 대상 클래스를 찾습니다.
  • 찾은 클래스는 **Spring Container(ApplicationContext)**에 Bean으로 등록됩니다.
  • Spring Container는 등록된 클래스의 객체를 생성(new Constructor())하여 메모리에 올립니다.

5. 핵심 클래스: ClassPathBeanDefinitionScanner

  • ClassPathBeanDefinitionScanner:
    • @ComponentScan의 내부에서 동작하는 클래스입니다.
    • 클래스 경로를 스캔하여, 특정 어노테이션(@Component, @Controller, @Service, @Repository)이 붙은 클래스를 감지하고 Spring Container에 Bean으로 등록합니다.

6. @ComponentScan과 AutoConfiguration

  • Spring Boot에서는 @ComponentScan과 함께 자동 설정 기능을 제공합니다.
  • 개발자가 직접 설정을 작성하지 않아도, @ComponentScan이 Controller, Service, Repository를 자동으로 등록하고, AutoConfiguration이 필요한 추가 설정을 제공합니다.
  • 이로 인해 DispatcherServlet, HandlerMapping, ViewResolver 같은 Spring MVC의 주요 구성 요소가 자동으로 메모리에 올라갑니다.

7. 결론

  1. **@ComponentScan**은 Spring Container에 등록할 클래스를 자동으로 스캔하여 Bean으로 등록합니다.
  2. 주요 대상은 @Component, @Service, @Repository, @Controller 어노테이션이 붙은 클래스입니다.
  3. Spring MVC에서 요청 처리를 위한 HandlerMapping과 Controller 매핑 정보를 구성하는 데 핵심 역할을 합니다.
  4. Spring Boot에서는 @SpringBootApplication 내부에 기본적으로 포함되어 있어, 추가 설정 없이도 자동으로 동작합니다.
  5. 필요할 경우 스캔 범위를 커스터마이징하거나, 대상 클래스를 필터링하여 사용할 수 있습니다.