ServletContext, ApplicationContext, WebApplicationContext 비교
[Java Servlet]
자바 서블릿 (Java Servlet) 은 자바를 사용하여 웹페이지를 동적으로 생성하는 서버측 프로그램 혹은 그 사양을 말하며, 흔히 “서블릿”이라 불린다. 자바 서블릿은 웹 서버의 성능을 향상하기 위해 사용되는 자바 클래스의 일종이다. 자바 EE 사양의 일부분이다.
생명주기
1) 서블릿 컨테이너가 서블릿 인스턴스의 init() 메소드를 호출하여 초기화 한다. 최초 요청을 받았을 때 한번 초기화 하고 나면 그 다음 요청부터는 이 과정을 생략한다.
2) 서블릿이 초기화 된 다음부터 클라이언트의 요청을 처리할 수 있다. 각 요청은 별도의 쓰레드로 처리하고 이때 서블릿 인스턴스의 service() 메소드를 호출한다.
● 이 안에서 HTTP 요청을 받고 클라이언트로 보낼 HTTP 응답을 만든다.
● service()는 보통 HTTP Method에 따라 doGet(), doPost() 등으로 처리를 위임한다.
● 따라서 보통 doGet() 또는 doPost()를 구현한다.
3) 서블릿 컨테이너 판단에 따라 해당 서블릿을 메모리에서 내려야 할 시점에 destroy()를 호출한다.
[servlet Container]
“서블릿들을 보관하는 그릇(컨테이너)”
서버에서 만들이진 서블릿이 스스로 동작하는 것이 아니라, 서블릿을 관리해주는 것이 필요한데, 이 역할을 하는 것이 서블릿 컨테이너이다.
서블릿 컨테이너는 Clinet의 Request를 받아주고 Response할 수 있게, 웹 서버와 소켓을 만들어 통신하며 대표적인게 톰캣(Tomcat) 이다.

서블릿 컨테이너의 역할
1) 웹서버와의 통신 지원
서블릿 컨테이너는 서블릿과 웹서버가 손쉽게 통신할 수 있게 해주어, 소켓을 만들고 listen, accept 등을 API로 제공하여 복잡한 과정을 생략할 수 있게 해준다.
2) 서블릿 생명주기(Life Cycle) 관리
● 서블릿 클래스를 로딩하여 인스턴스화
● 초기화 메소드를 호출
● 요청이 들어오면 적절한 서블릿 메소드를 호출합니다.
● 서블릿 소멸 시 Garbage Collection(가비지 컬렉션)을 진행
3) 멀티스레드 지원 및 관리
● 서블릿 컨테이너는 요청이 올 때 마다 새로운 자바 스레드를 하나 생성한다.
● HTTP 서비스 메소드를 실행하고 나면, 스레드는 자동으로 소멸한다.
● 원래는 스레드를 관리해야 하지만 서버가 다중 스레드를 생성 및 운영해주니 스레드의 안정성에 대해서 걱정하지 않아도 된다.
● 요청이 올때마다 스레드를 만들고 없애는것은 오버헤드가 크다. 그러므로 스레드 풀(Thread pool) 사용 (Tomcat은 스레드 풀을 사용한다.)
스레드 풀 내부에 스레드를 저장하고, 필요할때마다 꺼내서 사용하고 다시 반납한다. 스레드 개수 이상의 요청이 올 경우 초과되는건 wait
4) 선언적인 보안 관리
● 서블릿 컨테이너를 사용하면 개발자는 보안에 관련된 내용을 서블릿 또는 자바 클래스에 구현해 놓지 않아도 된다.
● 일반적으로 보안관리는 XML 배포 서술자에 기록하므로, 보안에 대해 수정할 일이 생겨도 자바 소스 코드를 수정하여 다시 컴파일 하지 않아도 보안관리가 가능합니다

동적 페이지
-
사용자가 URL을 클릭하면 HTTP Request를 Servlet Container에 보낸다.
-
Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체를 생성한다.
-
사용자가 요청한 URL을 분석하여 어느 서블릿에 대한 요청인지 찾는다.
-
컨테이너는 서블릿 service() 메소드를 호출하며, POST, GET여부에 따라 doGet() 또는 doPost()가 호출된다.
-
doGet() or doPost() 메소드는 동적인 페이지를 생성한 후 HttpServletResponse객체에 응답을 보낸다.
-
응답이 완료되면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다.
[ServletContext]

톰캣이 실행되면서 생성된다.
서블릿 컨텍스트(ServletContext)란 하나의 서블릿이 서블릿 컨테이너와 통신하기 위해서 사용되어지는 메서드들을 가지고 있는 클래스이다.
하나의 web application 내에 하나의 컨텍스트가 존재한다. web application내에 있는 모든 서블릿들을 관리하며 정보공유할 수 있게 도와 주는 역할을 담당한다.
사용 예시)
서블릿 컨테이너에서 요청을 처리 할 서블릿을 찾아서 요청을 보내거나 파일의 MIME TYPE을 가져오거나 할 때 서블릿 컨텍스트의 메서드를 사용할 수 있다.
(공식문서 : https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/javax/servlet/ServletContext.html?is-external=true)
Web Service Architecture

[Application Context]
스프링에서는 오브젝트의 생성과 관계 설정, 사용, 제거 등의 작업을 애플리케이션에서 개발자가 코드를 직접 구현하는 대신 독립된 컨테이너가 담당하는데 이를 컨테이너가 제어권을 가지고 있다고 해서 IoC라고 부른다. 또한, 스프링에서는 IoC를 담당하는 컨테이너를 빈 팩토리 또는 애플리케이션 컨텍스트라고 부른다.
DI 관점에서 볼 때 IoC 컨테이너를 빈 팩토리라고도 하는데 스프링 컨테이너는 DI 작업보다 더 많은 일을 하고 이에 해당하는 필요한 여러 컨테이너 기능을 추가한 것을 애플리케이션 컨텍스트 라고 부른다.
실제 ApplicationContext 는 인터페이스이고, 스프링 컨테이너는 이 ApplicationContext를 구현한 구현체를 말한다.
애플리케이션 컨텍스트가 스프링 애플리케이션을 만들기 위해 아래와 같은 일을 한다.
● POJO 클래스
객체지향적인 원리에 충실하면서, 환경과 기술에 종속되지 않고 필요에 따라 재활용 될 수 있는 방식으로 설계된 오브젝트를 말한다.
● 설정 메타정보
POJO 클래스들 중에 애플리케이션에서 사용할 것을 선정하고 이를 IoC 컨테이너가 제어할 수 있도록 적절한 메타정보를 만들어 제공하는 작업이다.
IoC의 컨테이너의 가장 기초적인 역할은 오브젝트를 생성하고 관리하는 것이고 IoC 컨테이너가 관리하는 객체를 빈이라하고 설정 메타정보는 이 빈을 어떻게 만들고 어떻게 동작할 것인가에 대한 정보이다.
스프링의 설정 메타정보는 BeanDefinition 인터페이스로 표현되는 순수한 추상 정보고 애플리케이션 컨텍스트는 이 BeanDefinition으로 만들어진 메타정보를 담은 오브젝트를 사용해서 IoC와 DI작업을 수행한다.
그래서 xml, 애너테이션, 자바코드, 프로퍼티 파일이든 상관없이 BeanDefinition으로 정의되는 스프링의 설정 메타정보의 내용을 표현한 것이면 무엇이든 사용 할 수 있다.
여러 설정 파일들을 BeanDefinition으로 읽어주는게 BeanDefinitionReader라는게 있고 이거를 구현해서 BeanDefinition 타입으로 정의할 수만 있으면 어떤 설정 메타정보는 어떤 형식으로든 작성할 수 있다.
스프링 IoC 컨테이너는 각 빈에대한 정보를 담은 설정 메타정보를 읽어들인 뒤에, 이를 참고해서 빈 오브젝트를 생성하고 프로퍼티나 생성자를 통해 의존 오브젝트를 주입해주는 DI작업을 수행한다.
이 작업을 통해 만들어지고, DI로 연결되는 오브젝트들이 모여서 하나의 애플리케이션을 구성하고 동작하게 되는데 이것이 IoC 컨테이너(Application Context)의 역할이 됩니다.
BeanDefinition에서 정의되는 메타정보
● 빈 아이디, 이름, 별칭 : 빈 오브젝트를 구분할 수 있는 식별자
● 클래스 or 클래스 이름 : 빈으로 만들 POJO 클래스 또는 서비스 클래스 정보
● 스코프
● 프로퍼티 값 또는 참조
● 생성자 파라미터 값 또는 참조
● 지연 로딩 여부
메타정보 리소스 : xml, annotation, properties 등
메타정보 리더 : BeanDefinitionReader라는 인터페이스
설정 메타정보: BeanDefinition라는 인터페이스
[WebApplicationContext]

ApplicationContext 를 확장한 인터페이스이다.
WebApplicationContext를 구현한 구현체들이 스프링 애플리케이션에서 가장 많이 사용된다. 구현체는 Xml 설정파일을 사용하는 XmlWebApplicationContext, 애너테이션 기반의 설정 리소스를 사용하는 AnnotationConfigWebApplicationContext등이 있다.
빈설정 메타정보를 이용해 빈 오브젝트를 만들고 DI작업을 수행하지만 그것만으로는 애플리케이션이 동작하지는 않는다. 마치 자바 애플리케이션의 main() 메서드처럼 어디선가 특정 빈 오브젝트의 메서드를 호출해야 애플리케이션이 동작이 된다.
보통 이런 기동시키는 역할을 맡은 빈을 사용하려면 IoC 컨테이너에서 요청해서 빈 오브젝트를 가져와야되고 만약 직접 IoC 컨테이너를 셋업했다면 다음과 같은 코드로 실행한다.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("...../conf/animal.xml");
PetOwner person = (PetOwner)context.getBean("id_petOwner");
person.play();
context.close();
적어도 한 번은 IoC 컨테이너에게 요청해서 빈 객체를 가져오고 이 때 getBean()을 사용해서 ApplicationContext안에 있는 객체를 가져온다.
그 이후로는 다시 빈으로 가져오지 않아도 되는데 빈 객체끼리 DI로 서로 연결되어 있으므로 의존관계를 타고 필요한 객체가 호출되면서 애플리케이션이 동작이 된다.
IoC 컨테이너의 역할은 이렇게 초기에 빈 객체를 생성하고 DI한 후 최초로 애플리케이션을 기동할 빈을 제공해주는 것 까지이다.
하지만 웹 애플리케이션은 사실 동작하는 방식이 다르다. 독립형 자바 프로그램은 JVM에게 main() 메서드를 가진 클래스를 시작 시켜달라고 요청할 수 있지만 웹에서는 main() 메서드를 호출할 방법이 없다.
웹 환경에서는 main() 메서드 대신 서블릿 컨테이너가 브라우저로부터 오는 HTTP 요청을 받아서 해당 요청에 매핑되어 있는 서블릿을 실행시켜주는 방식으로 동작한다. 서블릿이 일종의 main()의 역할을 하는셈이다.

웹 애플리케이션에서 스프링 애플리케이션을 가동시키는 방법?
먼저 main() 역할을 하는 서블릿을 만들어두고, 미리 애플리케이션 컨텍스트를 생성해둔 다음, 요청이 서블릿으로 들어올 때마다 getBean() 으로 필요한 빈을 가져와서 정해진 메서드를 실행시키면 된다.
main() 메서드안에서 애플리케이션 컨텍스트를 만들고 설정 메타정보를 읽어들여서 초기화하고 빈을 요청하고 메서드를 실행하는 것과 다를게 없다. main()메서드나 테스트 메서드에서 했던 작업을 웹 애플리케이션과 그에 소속된 서블릿이 대신 해줄 뿐이다.
그리고 앞에서 설명했듯 서블릿 컨테이너는 사용자의 요청을 받아서 서블릿을 동작시켜주는 일을 맡는다. 서블릿은 웹 애플리케이션이 시작될 때 미리 만들어둔 웹 애플리케이션 컨텍스트에게 빈 객체로 구성된 애플리케이션의 기동 역할을 해줄 빈을 요청해서 받아두고 미리 지정된 메서드를 호출함으로써 스프링 컨테이너가 DI방식으로 구성해둔 애플리케이션의 기능이 시작되는 것이다.
우리가 이런 설정을 하지않았지만 잘 동작하는 것은 웹 환경에서 애플리케이션 컨텍스트를 생성하고 설정 메타정보로 초기화해주고, 클라이언트로부터 들어오는 요청마다 적절한 빈을 찾아서 이를 실행해주는 기능을 가진 ‘DispathcerServlet’이라는 이름의 서블릿을 스프링에서 제공하고 이를 우리가 사용하기 때문이다.
Spring에서 DispathcerServlet은 web.xml 파일에 등록을 했었고 springboot에서는 SpringAutoConfiguration에 의해서 spring.factories안에 있는 DispathcerServletAutoConfiguration이 명시 되어 있는것을 볼 수 있으며 이 객체를 통해 DispatcherServlet을 등록하게 된다.
댓글남기기