인프런 커뮤니티 질문&답변

김경현님의 프로필 이미지
김경현

작성한 질문수

토비의 스프링 부트 - 이해와 원리

자바코드 구성 정보 사용

안녕하세요 토비님. 강의중 질문있습니다.

해결된 질문

작성

·

347

0

안녕하세요 강의 잘 듣고있는 학생입니다.

다름이 아니라 applicationContext의 생성과정이 아직 스스로 정리가 되어있지 않아 이렇게 질문을 드립니다..

우선 제 생각은 이렇습니다.

applicationContext를 생성하면서 내부적으로 onRefresh() 를 오버라이딩을 합니다.

여기서

ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);

을 통해서 등록된 Bean을 들고오게 됩니다.

여기서 드는 의문점1은, this.getBean(DispatcherServlet.class)을 한다는 것은 이미 DispatcherServlet이 Bean등록이 되어있다는 것이고 그렇다면 applicationContext라는 변수를 만들기 전에 이미 Bean이 등록이 되어있었다고 생각됩니다.

그러면 applicationContext라는 변수를 방금 막 선언하고 아직 객체를 할당하는 과정인데 this.getBean이 작동한다?

this는 분명 applicationContext인데 어떻게 applicationContext안의 getBean을 통해 dispatcherServlet등이 불러와지는지 모르겠습니다.. (요약하면, 아직 인스턴스를 만들지 않았는데 어떻게 applicationContext안의 getBean이 동작할 수 있는가? 입니다)

 

두번째는, 어떻게든 위의 과정을 거쳐서 applicationContext(스프링 컨테이너)가 서블릿 컨테이너와 연결이 되었습니다. 이후 applicationContext.register(HellobootApplication.class)를 하게되는데, 이미 위에서 빈 등록도 다 하고 모든걸 가지고 있는것 같은데 왜 register가 필요한것인지 모르겠습니다 ㅠㅠ

register하는 코드는

HellobootApplication.class라는 클래스 구성정보를 읽어서 그 내용을 토대로 빈(이때 이 빈은 HellobootApplication 빈 일까요??)을 등록한다 라고 생각되는데, HellobootApplication 클래스의 정보에는 팩토리 메서드 2개(ServletWebServerFactory,DispatcherServlet) 와

applicationContext를 구성하는 코드밖에 없다고 생각됩니다. applicationContext를 구성하는 과정에서 이미 팩토리 메서드 정보를 사용한 것 같은데, 그렇다면 이미 빈을 만드는데 필요한 정보는 다 가지고 있는것이 아닌가? 라고 생각이 듭니다. 이런 부분들이 자꾸 맘에 걸려서 다음강의로 못넘어가겠습니다 ㅠㅠ 명확하게 정리해주시면 감사하겠습니다..

답변 3

0

토비님의 프로필 이미지
토비
지식공유자

익명 클래스를 이용해서 onRefresh를 오버라이드한 부분을 말씀하시는 것이군요.

여기서 onRefresh()는 new AnnotationConfigWebApplicationContext()로 오브젝트가 만들어질 때 실행되는 게 아닙니다. 여기서 만들어지는 오브젝트의 한 메소드일 뿐이죠. 이게 실행되는 시점은 가장 아래 refresh()를 호출해서 applicationContext의 내부 빈을 초기화 한 다음이죠. 그때 위에 정의한 onRefresh()의 코드가 실행됩니다.

익명클래스처럼 메소드 내부에서 클래스가 재정의되는 경우에는, 코드가 나열되 순서와 실행 순서가 일치하지 않습니다.

 

김경현님의 프로필 이미지
김경현
질문자

답변 감사합니다.

그렇다면 맨 밑줄 바로위의 register는 어떤행동을 하는걸까요?

이미 HelloApplication 내부의 팩토리 메서드를 통해 빈 등록도 했고, 스프링컨테이너와 서블릿컨테이너도 연결했는데, 무엇을 위한것인지 잘 모르겠습니다.

구체적으로 어떤일을 하는지 궁금합니다.

토비님의 프로필 이미지
토비
지식공유자

register()가 HelloApplication 클래스를 빈으로 등록해주는 역할을 하는 거죠.

main() 메소드가 실행됐다고 HelloApplication 클래스가 빈으로 저절로 등록되는 게 아닙니다. 따라서 @Bean 팩토리 메소드도 빈이 되지 않죠. 그게 정의된 클래스를 스프링의 빈으로 쓰겠다고 applicationContext에 등록해줘야 합니다.
main()은 static 메소드죠. 이건 HelloApplication 클래스 안에 넣어놨을 뿐 전혀 상관없는 코드입니다. main()이 실행된다고 HelloApplication 클래스가 알아서 스프링 애플리케이션 컨텍스트에 등록되지 않습니다.
그래서 register()를 호출해서 직접 등록해줘야 합니다.

김경현님의 프로필 이미지
김경현
질문자

아..!

그럼 실제 main()이 실행되고 register이후 refresh가 되면서 팩토리 메서드 정보로 빈을 생성하고 서블릿컨테이너와도 연결을 하게 되면서 applicationContext 빈이 생성되는것이군요.

늦은 시간에 답변해주셔서 감사합니다!

0

토비님의 프로필 이미지
토비
지식공유자

강의 어느 단계의 코드인지를 잘 모르겠어서 답변을 드리기가 쉽지 않네요. 워낙 많은 단계가 있어서요.

말씀하시는 내용이 담긴 메소드 코드 전체를 옮겨주시면 설명드리겠습니다.

김경현님의 프로필 이미지
김경현
질문자

Bean의 생명주기 메소드 << 이 부분입니다!

package tobyspring.helloboot;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;



@Configuration
@ComponentScan
public class HellobootApplication {

       @Bean
       public ServletWebServerFactory servletWebServerFactory(){
          return new TomcatServletWebServerFactory();
       }
       @Bean
    
       public DispatcherServlet dispatcherServlet(){
          return new DispatcherServlet();
       }
    public static void main(String[] args) {
       System.out.println(ServletWebServerFactory.class);

       AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(){

          @Override
          protected void onRefresh() {
             super.onRefresh();
             ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
             DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);

           

             WebServer webServer = serverFactory.getWebServer(servletContext -> {
                servletContext.addServlet("dispatcherServlet",dispatcherServlet
                      ).addMapping("/*");
             });

             webServer.start();
          }
       };

       applicationContext.register(HellobootApplication.class);
       
       applicationContext.refresh();



    }


}

 

0

김경현님의 프로필 이미지
김경현
질문자

아.. 뭔가 제가 this를 잘못 알고있는 것 같네요..

this 가 new AnnotationConfigWebApplicationContext
오브젝트라면, 이 오브젝트가 beanFactory를 참조해서 현재 등록된 빈 정보를 통해 getBean()을 하고 이렇게 얻어진 서블렛 컨테이너를 스프링 컨테이너에 연결을 한다.

라고 다시 생각되는군요..
그렇다면 applicationContext.register(HellobootApplication.class); 는 어떻게 해석하는게 옳을까요?
applicationContext는 이미 서블렛 컨테이너와 연결된 것을 알고 있을텐데, 이걸 등록해야하는 이유는 뭘까요? ㅠㅠ 자꾸 의문이 의문을 낳는군요

김경현님의 프로필 이미지
김경현

작성한 질문수

질문하기