DispatchServlet에 의해 생성되어지는 수 많은 객체들은 어디서 관리될까?
DispatcherServlet에 의해 생성되어지는 수 많은 객체들은 ApplicationContext에서 관리된다. 이것을 IoC라고 한다.
ApplicationContext
IoC란 제어의 역전을 의미한다. 개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가르키는 레퍼런스 변수를 관리하기 어렵다. 그래서 스프링이 직접 해당 객체를 관리한다. 이때 우리는 주소를 몰라도 된다. 왜냐하면 필요할 때 DI하면 되기 때문이다.
DI를 의존성 주입이라고 한다. 필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져올 수 있다. ApplicationContext는 싱글톤으로 관리되기 때문에 어디에서 접근하든 동일한 객체라는 것을 보장해준다.
ApplicationContext의 종류에는 두가지가 있는데 (root-applicationContext와 servlet-applicationContext) 이다.
스프링부트의 작동순서를 간략하게 살펴보자
dispatchServlet이 동작하기전에 거치는 한 단계가 있는데
Servlet이 만들어지면 (요청만큼)스레드가 만들어진다.
스레드를 만든다는 것은 부하가 걸리기 쉽다고 할 수 있다.
그래서 모든 스레드가 공통적으로 사용하는 스레드가 있는데
이것을 DB커넥션이다.
혹은, 모든 스레드가 공통적으로 사용해도 되는 것은
Context Loader Listner가 띄워준다. ( root_Application Context라는 파일을 읽는다. )
a. servlet-applicationContext(웹과 관련된 정보만 가지고 있음 => 웹관련 어노테이션 스캔)
servlet-applicationContext는 ViewResolver, Interceptor, MultipartResolver 객체를 생성하고 웹과 관련된 어노테이션 Controller, RestController를 스캔 한다.
============> 해당 파일은 DispatcherServlet에 의해 실행된다.
b. root-applicationContext(db관련 객체 생성 ioc메모리에 올려준다)
root-applicationContext는 해당 어노테이션을 제외한 어노테이션 Service, Repository등을 스캔하고 DB관련 객체를 생성한다. (스캔이란 : 메모리에 로딩한다는 뜻)
============> 해당 파일은 ContextLoaderListener에 의해 실행된다. ContextLoaderListener를 실행해주는 녀석은 web.xml이기 때문에 root-applicationContext는 servlet-applicationContext보다 먼저 로드 된다.
당연히 servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만 그 반대는 불가능하다. 생성 시점이 다르기 때문이다.
필요한 객체를 applicationContext에 의해 등록하지 않아도 된다
Bean Factory
필요한 객체를 Bean Factory에 등록할 수 도 있다. 여기에 등록하면 초기에 메모리에 로드되지 않고 필요할 때 getBean()이라는 메소드를 통하여 호출하여 메모리에 로드할 수 있다. 이것 또한 IoC이다. 그리고 필요할 때 DI하여 사용할 수 있다. ApplicationContext와 다른 점은 Bean Factory에 로드되는 객체들은 미리 로드되지 않고 필요할 때 호출하여 로드하기 때문에 lazy-loading이 된다는 점이다.
ex)@Configuration을 명시한 어떤 클래스가 있다
이 클래스는 @Configuration를 명시해 컴포넌트 스캔 시 메모리에 뜬다.
이안에 객체를 return하는 메소드가 있다면 @Bean을 이용해 메모리에 띄울 수 있다.
@Configuration
class a {
@Bean
객체 메소드(){
return 객체
}
}