스프링의 핵심을 담당하는 것은 빈 팩토리
혹은 애플리케이션 컨텍스트
라고 불리는 것이다. 이 두 가지는 이전에 만들어본 DaoFactory
를 조금 더 일반화한 것이라고 설명할 수 있다.
스프링에서는 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트를 빈(bean)
이라고 부른다. 자바빈, 엔터프라이즈 자바빈에서 말하는 것과 비슷한 오브젝트 단위의 애플리케이션 컴포넌트를 말한다.
스프링 빈
은 스프링 컨테이너가 생성, 관계설정, 사용 등을 제어해주는 제어의 역전이 적용된 오브젝트를 가리킨다.
스프링에서 빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(Bean Factory)
라고 부른다. 빈 팩토리를 조금 더 확장하면 애플리케이션 컨텍스트(Application Context)
가 되며 IoC 방식을 따라 만들어진 일종의 빈 팩토리라고 생각하면 편하다.
앞으로 다룰 내용에서 빈 팩토리
와 애플리케이션 컨텍스트
는 동일하다고 봐도 무방하다. 빈 팩토리
는 빈을 생성하고 관계를 설정하는 IoC의 기본 기능에 초점을 맞추는 것이고, 애플리케이션 컨텍스트
는 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 좀 더 부각된다.
애플리케이션 컨텍스트는 별도의 설정 정보를 참고해서 빈의 생성, 관계설정 등의 제어 작업을 총괄한다. 설정 정보를 담고 있는 무엇인가를 가져와 이를 활용하는 범용적인 IoC 엔진같은 것으로 보면 된다.
이전에 DaoFactory
가 했던 설계도 역할을 하는 것이 애플리케이션 컨텍스트
와 설정정보
들이라고 보면 된다.
그 자체로 애플리케이션 로직을 담당하지는 않지만, IoC 방식을 이용해 애플리케이션 컴포넌트를 생성하고 관계를 맺어주는 등의 책임을 담당한다.
앞으로 스프링 프레임워크의 코드를 작성해야 하는데, 그 전에 의존성을 몇가지 추가해주어야 한다. 나는 Gradle
로 실습하여, Gradle
기준으로 작성하겠다.
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.22'
implementation group: 'org.springframework', name: 'spring-core', version: '5.3.8'
implementation group: 'org.springframework', name: 'spring-context', version: '5.3.8'
implementation group: 'commons-logging', name: 'commons-logging', version: '1.2'
}
test {
useJUnitPlatform()
}
org.springfraemwork
의 spring-core
, spring-context
commons-logging
의 commons-logging
DaoFactory
를 스프링의 빈 팩토리가 사용할 수 있는 설정정보로 만들어보자.
@Configuration
이라는 애노테이션을 클래스에 붙이면, 해당 클래스가 빈 팩토리
를 위한 오브젝트 설정을 담당하는 클래스라고 알릴 수 있다.@Bean
이라는 애노테이션을 객체 생성 메소드에 붙이면, 해당 메소드가 생성한 객체를 스프링 빈
으로서 활용할 수 있다.이 두 가지 애노테이션만으로 작성한 클래스를 스프링 프레임워크의 빈 팩토리
혹은 애플리케이션 컨텍스트
가 IoC 방식의 기능을 제공할 때 사용할 설정정보
로 만들 수 있다.
@Configuration // `애플리케이션 컨텍스트` 혹은 `빈 팩토리`가 사용할 설정 정보라는 표시이다.
public class DaoFactory {
@Bean // 오브젝트 생성을 담당하는 IoC용 메소드라는 표시이다.
public UserDao userDao() {
return new UserDao(getConnectionMaker());
}
@Bean // 오브젝트 생성을 담당하는 IoC용 메소드라는 표시이다.
public DSimpleConnectionMaker getConnectionMaker() {
return new DSimpleConnectionMaker();
}
}
public class UserDaoTest {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(DaoFactory.class);
UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
// 아래 주석처리된 방법과 같이 작성해도 무관하다.
// UserDao userDao = applicationContext.getBean(UserDao.class);
User user = new User();
user.setId("2");
user.setName("제이크2");
user.setPassword("jakejake");
userDao.add(user);
System.out.println(user.getId() + " register succeeded");
User user2 = userDao.get(user.getId());
System.out.println(user2.getName());
System.out.println(user2.getPassword());
System.out.println(user2.getId() + " query succeeded");
}
}
테스트를 실행했을 때도 정상적으로 실행됨을 볼 수 있다.
여태까지의 진행사항을 정리하면,
ApplicationContext
인터페이스에 AnnotationConfigApplicationContext()
구현체를 생성했다.AnnotationConfigApplicationContext()
를 구성하는데 필요한 설정 정보는 @Configuration
애노테이션을 적용한 DaoFactory.class
에서 가져왔다.UserDao
를 생성할 때, 단순히 new
생성자를 이용하지 않고 ApplicationContext
에 존재하는 UserDao
타입의 스프링 빈
을 가져왔다.사실 UserDao
타입의 스프링 빈
을 가져올 때, applicationContext.getBean(UserDao.class)
와 같은 방식으로 작성해도 되지만, 간혹 해당 빈을 생성하는 방식이나 구성을 다르게 하는 경우도 있어서 그러한 경우를 고려해서 직접 빈의 이름까지 작성해주는 방식도 존재하는 것이다.
사실 지금까지는 스프링을 적용하긴 했지만 오히려 앞에서 DaoFactory
를 이용해 간단히 처리하던 부분을 여러가지 외부 의존성 설치와 애노테이션 사용으로 조금 더 복잡하게만 만든 꼴이다.
뒤에서는 이렇게 스프링을 사용한 IoC를 이용하면 얻는 이점에 대해 알아보자.
기존 오브젝트 팩토리 방식과 스프링 애플리케이션 컨텍스트의 방식을 비교해보자.
일단, 기존 오브젝트 팩토리
에 대응되는 것이 스프링의 애플리케이션 컨텍스트
이다. IoC 컨테이너
, 스프링 컨테이너
, 빈 팩토리
모두 크게 보았을 때는 애플리케이션 컨텍스트
의 동의어다. 애플리케이션 컨텍스트
는 BeanFactory
를 상속하여 확장시킨 것이다.
DaoFactory
는 DAO
오브젝트를 생성하고, DAO
와 ConnectionMaker
구현체 간의 관계를 맺어주는 제한적인 역할을 했다. 반면, 애플리케이션 컨텍스트
는 애플리케이션에서 IoC를 적용해 관리할 모든 오브젝트에 대한 생성과 관계 설정을 담당한다.
단, 애플리케이션 컨텍스트
는 직접적인 관계 작성 코드는 없고, 생성정보와 연관관계 정보는 별도의 설정정보를 통해서만 얻는다. 때로는 외부 오브젝트 팩토리에 그 작업을 위임하고 그 결과를 가져다가 사용하기도 한다.
@Configuration
애노테이션이 붙은 클래스는 스프링 프레임워크(IoC)의 설정정보를 제공한다.@Bean
애노테이션이 붙은 생성 메소드는 스프링 프레임워크에 스프링 빈을 제공한다.이렇게 애플리케이션 컨텍스트
를 이용하면 얻는 이점은 다음과 같다.
DaoFactory
는 매번 필요할 때마다 팩토리 오브젝트를 생성해야 하는 번거로움이 있다. 애플리케이션 컨텍스트
를 이용하면 일관된 방식으로 원하는 오브젝트를 가져올 수 있다. 물론 팩토리 오브젝트를 생성할 필요도 없다.
애플리케이션 컨텍스트
의 역할은 단지 오브젝트 생성과 다른 오브젝트와의 관계 설정이 전부가 아니라, 오브젝트가 만들어지는 방식을 설정하는 방법, 시점과 전략을 다르게 가져가는 방법, 자동생성, 오브젝트 후처리, 정보의 조합, 설정방식 다변화, 인터셉팅 등 오브젝트를 효과적으로 사용할 수 있는 다양한 기능을 제공한다.
스프링 빈이 사용할 수 있는 기반 기술 서비스나 외부 시스템과 연동 등을 컨테이너 차원에서 제공해주기도 한다.
빈 이름으로 검색, 타입으로 검색, 특정 애노테이션 설정된 빈 등 다양한 방식으로 찾을 수 있다.
스프링이 IoC 방식으로 관리하여 직접 그 생성과 제어를 담당하는 오브젝트를 말한다.
스프링 IoC를 담당하는 핵심 컨테이너를 말한다. 빈 등록, 생성, 조회, 반환 등 기타 부가적인 빈 관리 기능을 담당한다. 보통은 빈 팩토리
를 바로 사용하기보다 이를 확장한 애플리케이션 컨텍스트
를 사용한다. BeanFactory
에는 getBean()
과 같은 메소드가 정의되어 있다.
빈 팩토리
를 확장한 IoC 컨테이너이다. 빈 팩토리
의 기능에 추가적으로 스프링이 제공하는 애플리케이션 지원 기능이 포함된다. 스프링에서는 애플리케이션 컨텍스트
라는 용어를 빈 팩토리
보다 더 많이 사용한다. ApplicationContext
는 애플리케이션 컨텍스트
가 구현하는 기본 인터페이스를 가리킨다.
빈 팩토리
는 빈의 생성과 제어 관점에서 쓰는 용어이고, 애플리케이션 컨텍스트
는 스프링이 제공하는 애플리케이션 지원 기능을 모두 포함해서 이야기하는 용어이다.
애플리케이션 컨텍스트
혹은 빈 팩토리
가 IoC를 적용하기 위해 사용하는 메타정보를 말한다. 보통 IoC에 의해 관리될 애플리케이션 오브젝트를 생성하고 구성할 때 사용된다. 애플리케이션의 청사진이라고도 한다.
애플리케이션 컨텍스트
, 빈 팩토리
와 같은 의미이다. 컨테이너를 그냥 스프링
이라고 부르는 사람도 있다.
애플리케이션 컨텍스트
, 빈 팩토리
, IoC 컨테이너
를 포함해 스프링이 포함하는 모든 기능을 통틀어 말할 때 사용한다. 그냥 스프링이라고 말하기도 한다.