Wanna be Brilliant Full-Stack Developer
2/28 SPRING 스프링 컨테이너 에서 'ApplicationContext'은 무엇인가? 본문
2/28 SPRING 스프링 컨테이너 에서 'ApplicationContext'은 무엇인가?
Flashpacker 2022. 2. 28. 13:10
DispatchServlet에 의해 생성되어지는 수 많은 객체들은 어디에서 관리 될까?
외부에서 Request요청이 오면 아파치는 머리속에 지울것이다.
스프링은 아파치가 동작할수가없다. 정적인 자원을 요청하는건 스프링에서는 없다.
스프링에서는 다 작업파일을 요청한다 서블릿을!
Reuqset를 하면 톰캣이 반응을 하는데 첫번째 관문에 WEb.xml이 있고 Web.xml에서 스프링 내부에 들어가기 위해서 두가지 일을 하는데 첫번째는 Frontcontroller 패턴을 쓴다고 했으니까 DispatchServlet이 동작을 하고
Component 스캔을 한다. DispatchServlet은 FrontController와 RequestDispatcher의 결합이다.
궁극적인 목적이 머냐면 주소의 분배이다. 어떤 주소가 왔을때 어디로가! 이렇게 분배를 하는일인데
애가 분배뿐만아니라 하나의 일을 더해야하는데 분배를 하기 위해서는 메모리에 떠있어야한다.
어떤 요청이 들어왔을때 어디로 가게하려면 어디로가게하려는 클래스들이 여러개 있다.
이 클래스들이 메모리에 떠있어야지 보낼수 있다. 메모리에 안떠있으면 보낼수가 없다.
그래서 1번으로 하는게 주소를 분배하기전에 자신이 가지고있는거 있죠. 자바에서는 src라는 폴더 안에 보통 전부다 모여있는데 그러면 자바파일이 여기 있고 폴더 안에 a라는 폴더와 b폴더안에는 자바 파알이 있을것이다.
이렇게 수많은 자바 파일들이 있을떄 애들이 메모리에 떠있어야한다.
애들이 static으로 만들어 있지 않으면 메모리에 떠야하려면 New를 해야한다!
흔히 Static으로 만들어 있느 ㄴ자바파일이랑 일반적인 자바파일은 다르다
static은 메인 메소드가 실행되기전부터 메모리에 떠있다. 그래서 이 집으로 비유해보자면
태초에 존재하는것들이 static이다.
우리가 객체로 메모리에 띄우는애들은 태초에 존재하는 아이들이 아니라 예를 들어 1990-2005, 1990-2050과 같이 생성과 사라짐이 일어날수 있는 애들이 객체이다. 특정한 타이밍에 메모리에 떳다가 특정한 타이밍에 메모리에서 사라지는 아이들이다.
최초에 떠있어야하는 애들도 있고 어느순간 생겼다가 사라져야하는 아이들도 있다는것으로 구분할수 있다.
자바파일에서는 우리가 만든 Class들이 메모리에 일단 떠있으려면 Static이 전부로 만들어져있으면
혼자서 쓰는 프로그램이 아니고 수백명이 접근할때 Static파일이 충돌나고 , 겹치고 굉장히 불편할수 도있고
당연히 자원은 하나밖에 없으니까 자원의 효율은 있겠지만 애들은 새로 태어나야되는 아이들이니까
대부분은 new되야하니까 new , new를 해서 메모리에 띄우는데
우리 스프링은 IOC를 한다.
내가 new를 하지않고 그 new를 DispatchServlet이 컴포넌트 스캔이라는것을 src(소스폴더)내부에 있는 모든 파일에 하여 한다.
스캔의 범위를 설정할수 있는데 스프링은 스프링부트 버전부터 ALL SCAN한다! 특정 패키지이하면 모든걸 스캔한다
우리가 프로젝트를 만들면 우리가 패키지를 com.cos.blog를 만들면 이 패키지 이하의 모든 작업파일들이 모여있으면 그러면 컴포넌트 스캔의 범위가 이 패키지 이하로 잡힌다.
DispatchServlet은 무엇을 하냐면 컴포넌트 스캔을 모든 작업파일을 전부 검사하고 필요한것들을 메모리에 올린다.
여기서 궁금한것이 머가 필요하고 머가 필요하지않은지 어떻게 구분하는가?
정해져있다. 그것은 Spring이 어노테이션 기법으로 !
어떻게 정해놓으냐면 @Controller라는게 있으면 애들은 컨트롤러의 역할을 할거야 , DispatchServlet 이 니가 스캔할때 이렇게 되어있는애들은 메모리에 다 띄우고 IOC에서 관리해! 컨트롤러 말고 @RestController도 있는데 애도 메모리에 띄어서 관리해, 그리고 @Configuration도 있는데 메모리에 다띄우고 , @Repository도 있는데 메모리에 다띄우고
@Service라는것도 있는데 메모리에 다 띄워!
특정 목적이 아닌 @Component라는게 있으니까 메모리에 다띄워! 이런 어노테이션을 자바 파일에서 찾아서 여기에 이게 있으면 메모리에 띄우고 없으면 안띄우고 이 자바파일에는 서비스가 있네, 이 자바파일에는 컨트롤러가 있네 와 같이 메모리에 이렇게 띄운다
이거를 누가 정한거냐면 스프링이 특정 목적을 위해서 정해놨다.
우리는 그러면 이 어노테이션들이 어떤역할을 하는지 배워야한다. 내가 왜 IOC컨테이너 메모리에 IOC컨테이너에 어떤 자바클래스를 객체로 띄우고싶으면 어떤 어노테이션으로 메모리에 띄울수있는지 방법을 알아야 사용할 수 있다.
우리가 커스텀한 HELLO라는 어노테이션을 만들어서 이게 붙으면 메모리에 띄우게 우리가 직접 만들 수 도 있다.
하지만 초보인 내가 굳이 만들필요는 없고 기본적으로제공되어있는 어노테이션으로 대부분의 웹서비스를 구현할수 있다. 우리는 나중에 공부를 다 해야한다. 하지만 지금 중요한것은 이 어노테이션들이 먼지가 중요한것이 아니라
이런것들을 붙어있는것을 DispatchServlet이 컴포넌트 스캔을 한다는 것이다.
그래서 메모리에 뜨면 무엇을 할수 있냐면 어디로 가라고 분배를 할수 있다는것이다.
이것이 DispatchServlet의 목적이다. 컴포넌트 스캔을 통하여 주소를 분배하는것!
근데 Web.xml에서 DispatchServlet 들어가기전에 ContextLoaderListener라는게 있는데
우리가 서블릿을 만들어지면 제일 처음에 스레드가 만들어지는데
그러면 요청한 사람에 따라서 100명이면 스레드가 20개만 만들어지기로 약속했으면 20개에 대한 스레드가 만들어진다 각각의 스레드는 독립적이기 떄문에 서로 영향을 받지 않는다.
A라는 첫번쨰 요청이 만들어오면 첫번째 스레드가 만들어지고 객체들이 만들어지면
두번쨰 요청이 들어오면 새로운 스레드가 만들어지고 새로운 객체가 만들어지니까 충돌날일이 없다.
근데 이 컴포넌트 스캔을 통해서 메모리에 IOC에 띄운다고 했는데 이렇게 띄우는것보다 이렇게 띄우면 스레드가 따로 관리가 되니까
이 모든 요청을 하는 애들이 공통적으로 써야하는것들이 있다.
데이터베이스 커넥션이다. DB에 관련된것, 모든 객체와, 모든 스레드가 공통적으로 사용해도 되는것들은 미리 ContectLoaderListener을 통해서 띄운다!
이 컨텍스트로더리스너는 어떤 xml파일을 읽냐면 Root-ApplicationContext라는 파일을 읽는데
이 파일을 xml파일로 내가 커스터마이징 할수도있고 자바파일로도 커스터마이징 할수도있는데
중요한건 ContectLoaderListener가 Root-ApplicationContext을 읽는다.
애를 읽으면 애가 무슨일을 하냐면 스레드마다 따로 관리해야되는 애들 말고 공통적으로 써야되는 애들을 메모리에 띄어준다. 그리고 IOC컨테이너에서 관리해준다!
ContectLoaderListener가 먼저 실행이 되고 DispatchServlet이 실행이 되니까 재미있는것이 머냐면
DB에서는 데이터베이스 이 객체에서는 이 DispatchServlet이 메모리에 띄운애들한테 접근을 못한다.
왜냐하면 DB에 먼저 띄우고 두번쨰가 DispatchServlet이 떳기 때문에 2번으로 뜬애가 1번이 접근을 못한다 왜냐하면 메모리에 안떴으니까
반대는 가능하다. DispatchServlet가 메모리에 띄운 애들은 DB에 접근이 가능하다.
데이터베이스 접근은 Root-ApplicationContext파일에서 메모리에 띄어서 IOC에서 필요할떄마다 접근해서 가져와서 사용할 수 있다.
Web.xml이 로딩이 되면 2번쨰로 ContextLoader가 로딩이 되고 그때 Root-Context.xml이 실행이 된다.
Root-Context.xml 실행이 되면 이걸 applicationContext.xml이라고도 부르는데 이때 각각 스레드에서 관리되는것들이 아니라 딱 하나만존재하면 되는것들, 모든 스레드들이 공유해서 사용하면 되는것들을 메모리에 띄운다.
모든 스레드마다 데이터베이스 커넥션에 new, new해서 만들필요는 없다.
어차피 모든 이 큰 스프링 컨테이너가 데이터베이스 커넥션 되는건 하나만 있으면 되기떄문에!
ApplcationContext
수 많은 객체 들이 ApplicationContext에 등록된다. 이것을 IOC라고 한다.
어떻게 등록이 되냐면 DispatchServlet이 컴포넌트 스캔할때 등록이 된다.
IOC라는것은 제어의 역전을 의미한다.
개발자가 직접 new를 통해 객체를 생성하게 된다면 해당 객체를 가르키는 레퍼런스 변수를 관리하기 어렵다. 그래서 스프링이 직접 해당 객체를 관리한다. 이 객체를 관리 하기위해서 우리를 공부해야하는것들은 어떤 어노테이션을 붙여야 IOC가 관리할수있게 메모리에 띄울수 있는지?
이렇게 띄어진 주소를 우리는 주소를 몰라도 된다. 왜냐하면 필요할 때 DI하면 되기 때문이다.
DI를 의존성 주입이라고 한다. 필요한 곳에서 ApplicationContext에 접근하여 필요한 객체를 가져올 수 있다.
결국 ApplicationContext에 모든 정보가 다 담겨 있다.
ApplicationContext는 싱글톤으로 관리되기 때문에 어디에서 접근하든 동일한 객체라는 것을 보장해준다.
ApplicationContext의 종류에는 두가지가 있는데 (root-applicationContext와 servlet-applicationContext) 이다.
( 여기서 Root라는건 최상단 에 있는 applicationContext라는거고 servlet이라는건 서블릿만 관리하는 applicationConetext라는것이다. servlet-applicationContext은 웹만 바라본다. 그래서 모든 정보를 가지고 있지는 않다. 웹과 관련된 정보를 가지고 있으면 된다. 웹과 관련된 어노테이션만 스캔한다! 그리소 주소분배를 한다!
a. servlet-applicationContext
servlet-applicationContext는 ViewResolver, Interceptor, MultipartResolver 객체를 생성하고 웹과 관련된 어노테이션 Controller, RestController를 스캔 한다.
============> 해당 파일은 DispatcherServlet에 의해 실행된다.
b. root-applicationContext( 스레드마다 관리해야하는 것이 아니라 딱 하나만 만들어져서 관리되면 된다)
root-applicationContext는 해당 어노테이션을 제외한 어노테이션 Service, Repository등을 스캔하고 DB관련 객체를 생성한다. (스캔이란 : 메모리에 로딩한다는 뜻)
============> 해당 파일은 ContextLoaderListener에 의해 실행된다. ContextLoaderListener를 실행해주는 녀석은 web.xml이기 때문에 root-applicationContext는 servlet-applicationContext보다 먼저 로드 된다.
당연히 servlet-applicationContext에서는 root-applicationContext가 로드한 객체를 참조할 수 있지만 그 반대는 불가능하다. 생성 시점이 다르기 때문이다.
Servlet WebApplicationContext는 웹 과 관련된 애들을 메모리에 띄우고 관리를 한다.
Root WebApplicationContext는 데이터베이스와 관련된 어떤일을 할수 있다.
데이터 소스에 접근을 한다든지 서비스에 접근하거나 레파지토리에 접근하는 일을 한다!
그리고 ApplicationContext가 아니라 Bean Factory라는 애도 있다.
Bean Factory
등록 하는 방법은? 어떤 클래스를 @Configuration 붙어 있어야하고 이떄 컴포넌트 스캔을 할때 해당 A라는 클래스가 메모리에 뜬다. 메모리에 뜨고나서 이안에 있는 메서드들이 리턴하는 객체가 있다면 이런 객체를 @Bean이라고 해서 메모리에 띄울수 있다. 클래스 위에 붙이는 애라서 성질이 조금 다르다
@Bean은
필요한 객체를 Bean Factory에 등록할 수 도 있다. 여기에 등록하면 초기에 메모리에 로드되지 않고 필요할 때 getBean()이라는 메소드를 통하여 호출하여 메모리에 로드할 수 있다. 이것 또한 IoC이다. 그리고 필요할 때 DI하여 사용할 수 있다. ApplicationContext와 다른 점은 Bean Factory에 로드되는 객체들은 미리 로드되지 않고 필요할 때 호출하여 로드하기 때문에 lazy-loading이 된다는 점이다. ( 필요할때 그 어떤 클래스에서 해당 메서드를 누군가가 사용하고자 할때 그떄 메모리에 뜬다)
'Some Memos > Spring 개념' 카테고리의 다른 글
2/28 Spring 마지막 응답(Response)하는 방법! (0) | 2022.02.28 |
---|---|
2/28 SPRING DispatcherServlet은 무엇인가? (0) | 2022.02.28 |
2/24 SPRING HTTP 쿼리 스트링, 주소 변수매핑! 에대해 알아보자 ! (0) | 2022.02.24 |
2/24 SPRING HTTP 4가지 요청방식 (0) | 2022.02.24 |
2/24 SPRING Controller 기본 동작 이해하기! (0) | 2022.02.24 |