TIL(2021-03-01)

tmdgusya·2021년 3월 1일
0

TIL

목록 보기
3/7

IoC Container

  • 자바 Configuratio file 로 web.xml 로 대체가 가능하다.
  • 을 통해서 AnnotationConfigWebApplicationContext 로 바꿔준뒤 (왜냐면 우리는 @Configuration 를 사용할 것이기 때문에)
  • 추가 해준뒤 에 contextConfigLocation 을 해준뒤 해당 위치를 추가해준다.
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
	<param-name>contextClass</param-name>
	<param-value>org.springframework.web.context.support.
AnnotationConfigWebApplicationContext</param-value>
</context-param>

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>ConfigurationFilePath</param-vlaue>
</context-param>
  • 이렇게 해서 실행시키게 되면 ContextLoaderListenerAnnotationConfigWebApplicationContext 를 생성할 때 ConfigurationFilePath 를 기반으로 해당 객체를 생성하게 됩니다. 그러면 ConfigurationFilePath 에 적혀있는 Bean 파일들이 해당 Context 안에 존재하게 됩니다.
  • 이 과정은 Spring 본문 옮기기 를 참조하여 읽으면 좋다. (내가 번역하고 있는 건데.. 오역이 있을 수도 있다. 확실히 MVC 를 공부하면서 저걸 참조하여 보니 더 공부가 잘된다. 조금이라도 번역해두길 잘했다.)
  • 코드를 살펴보면 WebApplicationContext 가 초기화 되는 시점에 ROOT_WEB_APPLICATION_CONTEXT_ ATTRIBUTEApplication Context 를 등록하는데 우리가 이 ROOT_WEB_APPLICATION_CONTEXT _ATTRIBUTE 로 꺼내쓸수 있는 것이다.
ApplicationContext ac = getServletContext().getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  • 이제야 IoC 에 대해서 조금씩 이해가 오기시작한다. 그니까 우리가 Bean 을 만들고 관리하는 것이 아닌 IoC Container 에 맡긴 뒤 우리는 해당 컨테이너에서 받아와서 쓰는 입장이 되는것이다. 그래서 Inversion of Controll (제어의 역전) 이라고 부르는 것 같다.

Front Controller

  • 우리는 Servlet 을 추가해줄 때 마다 Web.xml 에 해당 정보를 추가해주어야 한다. (이런것도 일련의 중복이라고 볼 수 있겠다.)
  • 여하튼 이렇게 하다보면 동일작업을 처리해줘야 하는 일도 생길 수 있는데, 그 때 마다 Filter 로 하기에는 너무 복잡하고, 계속하여 중복될 것이다. 그래서 FrontController 라는 개념이 등장하게 되었다.
  • 만약 Client 로 부터 Request 가 들어오면 FrontController 가 해당 요청을 처리해야할 Controller 에게 Dispatch 해준다. Spring 은 해당 FrontController 를 Dispatcher Servlet 으로 구현해 두었다.

Root WebApplicationContext

  • DispatcherServlet 안에서 만드는 Servlet 이나 그런것들은 DispatcherServlet 안으로 Scope가 제한된다. 그래서 다른 DispatcherServlet 에서는 해당 DispatcherServlet 에 대해 모르고 있다. 그런데 우리가 DispatcherServlet 간 같은 정보를 공유해야 할 때가 있는데 그래서 RootWebApplicationContext 를 구분지어 놓은 것이다. 해당 RootWebApplicationContext 의 내용은 서로 다른 DispatcherServlet 에서도 공유되어 사용될 수 있다. 그래서 RootWebApplicationContext 에 담긴 정보는 Web 에 관한 정보는 없으며, Service 와 Repositories 에 관련된 정보들이 존재한다.

Servlet WebApplicationContext

  • 여기에는 Dispatcher Servlet 안에서 생긴 Bean 들이 존재하는데 Controllers, ViewResolver, HandlerMapping 등 웹과 관련된 빈들의 정보가 담긴다.

위의 두 얘기를 살짝 종합하면..

  • Service, Repositories 등등은 ContextLoaderListener 쪽에 등록되어야 하고, Controller, ViewResolver, HandlerMapping 등은 이제 Dispatcher 쪽에 등록되어야 한다. 아래에서 init-param 을 통해서 해당 과정을 구현해볼 것이다.

Spring Dispatcher Servlet

  • 우리는 이제 Spring 이 제공해주는 Dispatcher Servlet 을 등록해야 한다. 우리가 적은 Annotation 을 해석해주고, 우리가 return 하는 값들을 제대로 해석해줄 수 있는 Dispatcher Servlet 을 말이다.
<servlet>
	<servlet-name>app</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextClass<param-name>
		<param-value>ACWA</param-value>
	<init-param>
	<init-param>
		<param-name>contextConfigLocation<param-name>
		<param-value>contextConfigFilePath</param-value>
	<init-param>
</servlet>
  • 뭐 이렇게 되면 ContextLoader 의 경우 Configuration File 에 Component Scan 을 통해서 exclude Filters = @ComponentScan.Filter(Controller.class) 를 통해서 Controller / ViewResolver / HandlerMapping 등등의 파일을 등록해야 하지 않을 것이다.
  • Dispatcher 는 반대로 저것들만 등록하면 될것이다~ 그건 자신의 현재파일에 맞게맞게 설정!
  • 이제 mapping information 을 통해서 내가 만든 dispatcher servlet 은 roach url 에 관련한 모든 요청을 처리하도록 하자!
<servlet-mapping>
	<servlet-name>roach</servlet-name>
	<url-pattern>/roach/*</url-pattern>
</servlet-mapping>

만약 이러한 상속 구조가 귀찮다면..

  • Dispatcher Servlet 에 모든 Bean 에 관한 정보를 등록할 수도 있다. 최근에는 Dispatcher Servlet 에 모든 Bean 을 등록하는 추세라고 한다. 하지만 이런 사항들도 알아두면 기술을 이해하는데 좋을 것 같다.

동작원리

HandlerMapping

  • Debugger 를 통해 DispatcherService 를 찾아가다보면 기본적으로 2가지 Handler 를 만들어서 사용하는데 거기에는 BeanNameUrlHandlerMappingRequestMappingHandlerMapping 이 있는데 우리가 BeanName 을 Url 과 동일하게 적었을때 해석해주는게 BeanNameUrlHandlerMapping 이녀석 이였나 보다. RequestMappingHandlerMapping 얘는 GetMapping 등등의 어노테이션을 해석해주는 녀석이다. 그리고 이 핸들러가 찾아올 수 있는지 일련의 테스트 과정을 거치면서 어떤 handler 를 써야하는지도 찾는다.

HandlerAdapter

  • 위의 과정을 거쳐 찾은 Handler 를 누가 실행시킬 수 있는가? 를 찾는 작업이다.
  • 기본적으로 HttpRequestHandlerAdapter , SimpleControllerHandlerAdapter , RequestMappingHandlerAdapter 가 존재한다.

참고..

  • 도중에 GET 일 경우 캐싱기능이용이 가능하므로, 그거에 대해 판단하는 것도 있다.
  • 이 부분을 코드로본건 처음이다. 이론만 알고 있었는데

처리

  • 이제 찾아온 HandlerAdapter 를 통해 요청을 처리한다.
  • 그리고 invokeHandlerMethod 를 통해서 해당 Controller 내에서 처리할 수 있는 Method 를 호출하게 된다. (자바의 리플렉션을 이용한다고 한다.) 그래서 특정 값이 리턴되면 이걸 또 return 값을 처리해줄 수 있는 Handler 를 찾게된다. 여기에는 15가지 정도가 있는데.. 이건 적지는 않겠다 너무 많다.

간단 요약

  1. 요청을 분석한다
  2. 요청을 처리할 핸들러를 찾는다.
  3. 해당 핸드러를 실행할 수 있는 핸들러 어뎁터를 찾는다
  4. 핸들러 어댑터를 사용해서 요청을 처리한다
  5. 예외가 발생했다면, 예외처리 핸들러에 요청 처리를 위임한다.
  6. 핸들러의 리턴값을 보고 어떻게 처리할지 판단하다.
    1. 뷰 이름에 해당하는 뷰를 찾아서 렌더링 한다
    2. @ResponseEntity 가 있다면 Converter 를 사용해서 응답 본문을 만든다.
  7. 응답을 보낸다.

회고

  • 한번 더 공부하면서 느끼는 것들이 많다. 사실 스프링은 잠깐 개념적인거만 본 수준이라 처음 해본 수준이랑 비슷하다. 개인적으로 서블릿을 공부하면서 내가 이전에 SpringDocumentation 에 번역해놓은 내용들을 다시보니 확실히 어떤 내용들인지 이해가 됬다.

  • 이펙티브 자바에서 이제 끝단원인 병렬 부분을 하고 있는데 아이템 하나를 이해하는데 시간이 상당히 오래걸린다. 그 만큼 배우는 것도 많은데 쓰레드라는게 참 왜 우리가 커스텀하게 쓰면 안좋다는지 알것 같다.

  • 이제 내일부터 코드스쿼드 스프링 과정이 시작되는데 스프링 과정동안에는 최대한 JavaDoc 방식으로 주석을 첨부해보려고한다.

profile
겸손해지고, 수용하는 자세

0개의 댓글