웹에서의 스프링 IoC/DI
드디어 토비의 스프링 vol2의 공부를 시작한다. 토비의 스프링 vol1의 내용을 생각해보면 객체를 생성, 삭제 및 관계를 설정해주는 DI/IOC와 여러가지 기술을 유연하게 도입하거나 변경하게 해주는 서비스 추상화, OOP를 통해 모듈화 할수 없는 공통적으로 자주 쓰이고 여러곳에 산재되어 있는 코드를 모듈화해주는 AOP가 있다. 이러한 기술들을 기반으로 코드를 간단하고 유연하게 작성하도록 해주는 것이 스프링의 철학을 설명하고 있다.
vol2의 경우 목차를 살펴보니 스프링 vol1의 경우 스프링의 근간이 되는 기술들에 다룬데 반하여 스프링을 사용하여 어플리케이션을 어떻게 작성하는지 실질적 업무에 쓰일수 있는(?) 기술에 대하여 나와있다. 하지만 이러한 기술들을 제대로 쓰려면 vol1을 꼭 봐야겠다는 생각도 하게된다.
vol2의 1장은 스프링의 IoC/DI에 대한 설명이 나온다. 스프링 컨테이너(빈생성, 삭제, 관계설정을 해주는)는 ApplicationContext라는 인터페이스를 상속한 클래스를 통해 구현된다.
여러가지 구현 클래스가 있겠으나 책에서 살펴본 클래스는 StaticApplicationContext와 GenericApplicationContext, GenericXmlApplicationContext, WebApplicationContext였다. 보통 스프링 컨테이너의 메타정보는 xml을 바로 읽어들인다고 생각하지만 중간에 BeanDefinition이라는 인터페이스가 있다는 것을 StaticApplicationContext를 통해 살펴보았는데 이는 예제 코드를 통해 살펴볼 것이다. 각 클래스의 특징은 다음과 같다.
StaticApplicationContext
코드를 통해 빈 메타 정보를 등록하기 위해 사용(실전에서는 사용하면 안된다.)
StaticApplicationContext context=new StaticApplicationContext();
BeanDefinition serviceDef=new RootBeanDefinition(MyService.class);
//<property name="name" value="service">에 해당
serviceDef.getPropertyValues().addPropertyValue("name", "service");
context.registerBeanDefinition("myService", serviceDef);
GenericApplicationContext
GenericApplicationContext는 가장 일반적인 애플리케이션 컨텍스트의 구현 클래스다. 실전에서 사용될 수 있는 모든 기능을 갖추고 있는 애플리케이션 컨텍스트다.
GenericApplicationContext 는 StaticApplicationContext와 달리 외부의 리소스에 있는 빈 설정 메타정보를 리더를 통해 읽어들여서 메타 정보로 전화해서 사용한다.
GenericXmlApplicationContext
GenericApplicationContext의 XmlBeanDefinition을 선언하는 불편을 해소시켜주는 클래스
WebApplicationContext
스프링에서 가장많이 사용하는 컨텍스트. 웹 환경에서 사용할 때 필요한 기능이 추가된 애플리케이션 컨텍스트다. 스프링 애플리케이션은 대부분 서블릿 기반의 독립 웹 애플리케이션으로 만들어지기 때문.
스프링은 주로 엔터프라이즈 웹 개발에 주로 쓰이는데, 스프링의 경우 소수의 서블릿을 두고 요청에 따라 기능을 제공하는 핸들러를 제공하는 프론트 컨트롤러 패턴을 사용한다고 한다. 이때 요청을 받는데 사용되는 서블릿을 스프링에서 제공하는데 이것이 DispatcherServlet이다. 해당 서블릿은 일전에 개발자로 활동할 당시 자주보았던 클래스인만큼 반갑기 까지 하다.
그런데 한가지 의문점이 생긴다. 어플리케이션 시작초기에 스프링 컨테이너가 메타정보를 읽어들여서 빈을 생성하여 생성한 빈으로 애플리케이션을 수행시키는데 일반적인 어플리케이션이라면 main()메소드에서 해당 작업을 수행하였으나 스프링 웹에서는 어디서 해당작업을 수행하는가 의문을 가진다.
답은 DispatcherServlet에서 웹 환경에서 애플리케이션 컨텍스트를 생성하고 설정 메타정보로 초기화해주고, 클라이언트로 부터 들어오는 요청마다 적절한 빈을 찾아서 이를 실행해준다. 스프링이 제공해준 서블릿을 web.xml에 등록하는 것만으로 웹 환경에서 스프링 컨테이너가 만들어지고 애플리케이션을 실행하는데 필요한 대부분의 준비는 끝난다.
[ web.xml ]
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
얼마 공부하지는 않았지만 많은 통찰력을 얻은 느낌이다. 이러한 통찰력을 얻을 때마다 빨리 필드에서 개발을 다시 하고 싶다는 생각을 하게 된다.