본문 바로가기

강의/토비의 스프링부트

Bean의 생명주기 메소

 

팩토리 메서드를 이용해서 빈 인스턴스를 생성하는 방법을 사용했다.

조금 더 간결하게 빈을 등록하는 방법을 알아보자.

 

나를 빈으로 등록해줘

클래스에 레이블을 붙여주는데

어노테이션을 이용해서 지정할 수 있다.

 

ComponentScan : Component 라는 어노테이션을 찾아서 빈으로 등록해줌

Controller와 Service에 @Component라는 annotation을 붙여주면 된다.

 

 

애플리케이션 기능을 담당하는것은 컨트롤러 서비스

 

TomcatServletWebsServerFactory, DispatcherServlet

standalone application을 만들기 위해서 존재하는데

이것도 bean으로 등록해보자

 

팩토리 메서드를 이용하여 빈으로 등록해보자.

 

디브패쳐 서블릿은 자기가 이용할 컨트롤러를 찾아야하기 때문에

스프링 컨테이너가 필요하다.

빈으로 등록할때는 application context를 어떻게 받아야 할가

 

spring container가 dispatcher servlet은 aplication context가 필요하구나 인식하고 알아서 주입해준다.

bean의 life cycle 메서드 개념을 알아봐야 한다.

 

intellij option : ctrl + h (type 하이라키)

 

dispatcher servlet이 구현하고 있는 인터페이스 중에 ApplicationContextAware라는 interface 있고

이걸 구현해서 dispatceher servlet을 만들었는데

인터페이스를 들어가서 보면

setApplicationContext 라는 메서드가 있는 것을 확인할 수 있다.

 

이게 뭐하는 인터페이스인가 찾아보면

빈을 컨테이너가 등록하고 관리하는 중에

컨테이너가 관리하는 오브젝트를 빈에다가 주입해주는 life cycle 메서드인 것을 알수있다.

이 인터페이스를 구현한 어떤 클래스가 스프링 빈으로 등록되면

스프링 컨테이너는 이것을 인터페이스 setter 메서드를 이용해서 주입해준다.

그래서 dispatcher servlet 은 application context를 우리가 주입해주지 않아도 알아서 주입받게 된다.

 

실제로 applicationContextAware의 구현체는 applicationContext를 주입받는지 확인해보자.

controller에 applicationContextAware를 상속받고 setApplicationContext를 override 해주었다.

 

package com.example.tobyboot.toby;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;

@RequestMapping("/hello")
@RestController
public class HelloController implements ApplicationContextAware {

    private final HelloService helloService;

    public HelloController(HelloService helloService) {
        this.helloService = helloService;
    }

    @GetMapping
    @ResponseBody
    public String hello(String name) {
        return helloService.sayHello(Objects.requireNonNull(name));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }
}

 

서버를 띄우기만 해도 application context 를 주입받고 있다는 것을 확인할 수 있어야한다.

 

 

applicatioContext 오브젝트도 빈 오브젝트로 취급하고 있다.

컨테이너 입장에서는 자기 자신이기도 하지만 빈으로 등록해서 사용한다고 보면된다.

 

 

 

package com.example.tobyboot.toby;

import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MySpringApplication {
    public static void run(Class<?> applicationClass, String... args) {
        // spring container 만드는 작업
        // 익명 클래스
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext() {
            @Override
            protected void onRefresh() {
                // 생략 하면 안됨.
                super.onRefresh();
                // 서블릿 컨테이너를 초기화하는 코드
                ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
                DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);
                // application context를 주입 (그러나 application context를 주입하지 않아도 스프링 컨테이너가 알아서 주입해준다.)
                // dispatcherServlet.setApplicationContext(this);

                // servlet container를 코드로 실행하면서 servlet을 등록하는 작업
                WebServer webServer = serverFactory.getWebServer(servletContext -> {
                    servletContext.addServlet("dispatcherServlet",
                                    dispatcherServlet)
                            .addMapping("/*");
                });
                // 톰캣 서블릿 컨테이너가 동작한다.
                webServer.start();
            }
        };
        // bean 등록
        applicationContext.register(applicationClass);
        // 초기화 작업
        applicationContext.refresh();
        System.out.println("Hello containerless Standalone Application");
    }
}
package com.example.tobyboot;

import com.example.tobyboot.toby.MySpringApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
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.servlet.DispatcherServlet;

@Configuration
@ComponentScan
public class TobybootApplication {

    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    public static void main(String[] args) {
        MySpringApplication.run(TobybootApplication.class, args);
    }


}

 

돌아와서 MySpringApplication -> SpringApplication으로 원복하였다.
그러나 servletWebServerFactory가 존재하지 않으면 application이 실행되지 않는 것을 볼 수 있다.
원인은 무엇일까?

 

package com.example.tobyboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
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.servlet.DispatcherServlet;

@Configuration
@ComponentScan
public class TobybootApplication {

    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    public static void main(String[] args) {
        SpringApplication.run(TobybootApplication.class, args);
    }


}

 

 

'강의 > 토비의 스프링부트' 카테고리의 다른 글

ㅇㄹㄴㅇ  (0) 2023.02.22
테스트 코드  (0) 2023.02.22
자바코드 구성 정보 사용  (0) 2023.02.21
di 적용  (0) 2023.02.20
Dependency injection  (0) 2023.02.20