Spring 애플리케이션은 POJO + 메타 정보 + 스프링 프레임워크(IoC Container) 3 가지로 구성된다. 비즈니스 로직을 가지고 있는 POJO와 애플리케이션 구성 정보를 가지는 메타정보를 IoC Container인 스프링 프레임워크가 조합해서 스프링 애플리케이션을 구성하게 된다.
이 요소들에 대해서 좀 더 상세하게 알아보자.
POJO
POJO란 Plain Old Java Object의 약자로 말 그대로 이전부터 사용하던 평범한 자바 객체를 의미하는데 객체를 만들 때 특별히 무언가를 상속받아서 확장 할 필요가 없다는 것을 강조하기 위한 말이다.
스프링 이전의 프레임워크였던 EJB에서는 객체를 구성할 때 특별한 클래스를 상속받아야 하는 등 제약이 많았다. 스프링에서는 이런 제약사항 없이 그냥 클래스를 만들면 되기 때문에 강조된 개념이다. POJO로 작성하면 특정 기술이나 스펙에 종속되지 않는다.
스프링과 같은 프레임워크는 비지니스 로직이 빠져있는데 일반적으로 비즈니스 로직을 제공하는 클래스를 작성할 때 POJO로 작성해 주면 된다. 스프링 프레임워크에서는 이런 객체를 빈(Bean)이라고 부르며 관리하므로 스프링을 빈의 컨테이너(Container)라고 부른다.
빈으로 만드는 대상은 스코프에 따라 여러 종류가 있을 수 있는데 일반적으로 상태를 갖지 않고(stateless)비즈니스 로직으로만 구성되어 재사용이 가능한 객체들이다. 흔히 DAO나 Service 레이어를 구성하는 객체를 생각해볼 수 있다.
프레임워크를 사용하기 이전에는 이런 객체를 구성할 때 하나만 만들고 재사용하기 위해 Singleton 디자인 패턴을 적용해서 만들곤 했는데 스프링에서는 특별한 코딩 없이 이런 빈들을 Singleton으로 관리해 준다.
메타정보
메타 정보는 스프링 애플리케이션 구성을 위한 다양한 정보로 구성된다. 앞서 설명했던 POJO를 어떻게 빈으로 구성할 것인가에 대한 정보 즉 빈들의 생성이나 관계 설정도 메타 정보의 한 부분이다. 메타 정보를 작성할 때는 xml config, annotation, java config 3가지 방식을 사용할 수 있다.
말로는 복잡한데 다음의 예는 xml 기반으로 메타 정보를 작성한 예이다.
<!-- BoardRepoDevImpl 타입의 빈 boardRepo를 만들겠다.. -->
<bean id="boardRepo" class="com.example.core.repo.BoardRepoDevImpl">
</bean>
<!-- BoardServiceImpl 타입의 빈 boardService를 만들고 boardRepo를 주입하겠다. -->
<bean id="boardService" class="com.example.core.service.BoardServiceImpl">
<property name="boardRepo" ref="boardRepo" />
</bean>
xml 기반으로 작성해보니 뭔가 복잡해 보이긴 하는데 java 기반으로 보면 별거 없다.
@Configuration
public class BoardConfig {
@Bean
public BoardRepo boardRepo() {
return new BoardRepoDevImpl();
}
@Bean
public BoardService boardService(BoardRepo brepo) {
return new BoardServiceImpl(brepo);
}
}
생소한 에너테이션이 몇개 있긴 하지만 그냥 자바 객체 만드는 코드여서 전혀 어렵지 않다.
최근에는 xml config 방식보다는 java config + annotation 방식이 사용되고 있으며 SpringBoot에서는 application.yml 파일에도 일부 설정이 추가된다.
앞서 생성한 QuickStart 애플리케이션에서는 우리가 모르는 사이에 java config + annotation 방식으로 처리되었다.
스프링 프레임워크(=IoC Container)
앞서 언급했듯이 스프링 프레임워크는 POJO와 메타 정보를 이용하는 반제품 형태의 애플리케이션이다.
이 스프링 프레임워크의 역할이 여러 가지가 있는데 그중 무엇보다도 중요한 하나는 빈의 컨테이너로서 빈의 life cycle을 관리하는 역할이다. 스프링 프레임워크는 빈 객체의 생성(new), 빈 객체 간 관계 설정(set), 빈 객체 관리(singleton 등)를 관장한다.
프레임워크 이전에는 이런 작업들은 개발자가 코드로 제어하는 부분이었다. 하지만 이제 개발자가 POJO와 함께 메타정보를 넘겨주면 컨테이너로써의 스프링이 처리한다. 따라서 이제 개발자는 스프링이 원하는 형태로 코드를 작성해야 한다.
이제는 거꾸로 개발자의 코드가 제어를 받는 상태가 된 것이다. 이런 현상을 제어의 역전(IoC: Inversion Of Control)이라고 부르고 스프링 컨테이너를 IoC Container라고 부르게 된다.(프레임워크들은 대부분 제어가 역전된다.)
프로그래밍에서 IoC Container의 구현체는 ApplicationContext이다. 따라서 Spring Container, IoC Container, ApplicationContext 모두 같은 의미로 사용된다.
뭉쳐보면...
위에서 설명한 3가지 요소를 뭉쳐보면 다음과 같다.
개발자는 POJO를 작성하고 어떻게 구성할 것인지에 대한 메타 정보를 작성해서 스프링 프레임워크에 넘겨주면 스프링은 이 정보를 참조하여 필요한 빈 객체를 생성하고 관계를 설정해서 애플리케이션이 동작하도록 한다.