토비의 스프링 Vol2 1.5 스프링 3.1의 IoC 컨테이너와 DI

Soonwoo Kwon·2022년 6월 7일
0

토비의 스프링

목록 보기
11/11

1.5 스프링 3.1의 IoC 컨테이너와 DI

스프링 3.1에 새로 도입된 IoC/DI 기술은 다음 두 가지이다.

  • 강화된 자바 코드 빈 설정
  • 런타임 환경 추상화

스프링 3.1의 가장 큰 특징은 자바 코드를 이용한 설정 메타정보 작성이 쉽다는 점이다. 따라서 XML을 최소화하여 개발이 가능하다.

1.5.1 빈의 역할과 구분

빈의 종류

애플리케이션 로직 빈

빈이란 IoC/DI 컨테이너에 의해 생성되고 관리되는 오브젝트이다. 애플리케이션 로직 빈은 DAO와 같이 데이터 로직을 다루거나, 비즈니스 로직을 다루는 서비스 오브젝트, 컨트롤러 오브젝트가 있다.

애플리케이션 인프라 빈

DAO가 사용하는 DataSource 오브젝트는 여러 DAO 빈과 관계를 맺고 사용된다.
트랜잭션 추상화에 사용되는 DataSourceTransactionManager 또한 DataSource 오브젝트와 관계를 맺으며 DB 커넥션에 대한 트랜잭션을 책임진다.
이러한 빈들은 애플리케이션 동작에 참여하지만 로직을 담당하지 않으므로 애플리케이션 인프라스트럭처 빈이라고 부른다.

컨테이너 인프라 빈

DefaultAdvisorAutoProxyCreator는 Adivsor 타입 빈의 포인트컷 정보를 이용해 카깃 빈을 프록시로 바꿔준다. 애플리케이션 로직을 담고 있지 안흥며 애플리케이션 로직을 담은 빈과 관계를 맺어 사용되지 않는다.
대신 스프링 컨테이너의 기능에 관여한다. 이렇게 스프링 컨테이너의 기능을 확장해서 빈의 등록과 생성, 관계설정, 초기화 등의 작업에 참여하는 빈을 컨테이너 인프라스트럭쳐 빈이라고 한다.

컨테이너 인프라 빈과 전용 태그

컨테이너 인프라 빈 등록은 태그로도 가능하지만 전용 태그를 더 많이 사용한다.

스프링 Ioc/DI 컨테이너에는 기본적으로 @Configuration/@Bean을 이용해 새로운 빈을 등록하는 기능이 없다. 따라서 추가적인 설정이 없다면 @Configuration에 해당하는 클래스만 빈으로 등록된다.

<context:annotation-config>

XML에 위의 전용 태그가 추가되어야 한다. 이 설정으로 인해 추가적으로 등록되는 컨테이너 인프라빈들의 역할을 살펴보자

  • ConfigurationClassPostProcessor:
    • @Configuration과 @Bean을 이용해 새로운 빈을 등록하도록 한다.
  • AutowiredAnnotationBeanPostProcessor
    • @Autowired가 붙은 필드를 찾아 빈 의존관계를 설정한다.
  • CommonAnnotationBeanPostProcessor
    • @PostConstruct가 붙은 메소드를 빈이 초기화된 뒤에 호출한다.

빈의 역할

빈의 메타정보에는 ROLE가 명시되어 있다.

ROLE_APPLICATION

애플리케이션 로직 빈과 애플리케이션 인프라 빈처럼 애플리케이션이 동작하는 중에 사용되는 빈

ROLE_SUPPORT

복합 구조의 빈을 정의할 때 보조적으로 사용되는 빈

ROLE_INFRASTRUCTURE

전용 태그로 등록되는 컨테이너 인프라빈

1.5.2 컨테이너 인프라 빈을 위한 자바 코드 메타정보

스프링 빈의 역할을 나누는 이유는 빈의 역할에 따라 설정 메타정보 작성을 다르게 할 수 있기 때문이다.

IoC/DI 설정 방법의 발전

스프링 1.x

  • XML을 이용한 빈 등록 방식
  • 애플리케이션 로직 빈, 애플리케이션 인프라 빈, 컨테이너 인프라 빈이 모두 모여 복잡한 설정파일이 생성된다.

스프링 2.0

  • 컨테이너 인프라 빈을 위한 전용태그

스프링 2.5

  • 빈 스캐너와 스테레오타입 애노테이션을 이용한 빈 자동등록 방식과 애노테이션 기반의 의존관계 설정
  • 애플리케이션 로직 빈을 등록하기 위해 @Component와 같은 애노테이션을 사용
  • 애플리케이션 인프라 빈, 컨테이너 인프라 빈, 외부에서 작성된 클래스 빈에는 여전히 XML 설정파일을 이용

스프링 3.0

  • 자바 코드로 설정 정보를 대체
  • 컨테이너 인프라 빈 등록에는 XML 전용 태그가 필요

스프링 3.1

  • 컨테이너 인프라 빈도 자바 코드로 등록

자바 코드를 이용한 컨테이너 인프라 빈 등록

@ComponentScan

XML에서 <context:component-scan> 전용 태그를 사용한 것처럼 스테레오타입 애노테이션이 붙은 빈을 자동으로 스캔해서 등록한다.
엘리먼트 값으로 base 패키지를 넣어준다.

@ComponentScan(base)

또는 basePackageClasses 엘리먼트를 이용해 마커 클래스나 인터페이스를 넣어 주어도 된다.

@ComponentScan(basePackageClasses=ServiceMarker.class)

마커 클래스나 인터페이스를 이용할 경우 오타로 인한 에러가 컴파일 과정에서 발견되기 때문에 안전하다.
excludeFilters 엘리먼트에 @Filter 애노테이션을 지정해 스캔할 패키지에서 제외할 대상을 지정할 수도 있다.

@Import

다른 @Configuration 클래스를 빈 메타정보에 추가할 때 사용한다.

@Configuration
#Import(DataConfig.class)
public class AppConfig{
}

@Configuration
public class DataConfig{
}

위 설정 코드로 AppConfig 클래스 설정 정보에 DataConfig 클래스의 빈 정보가 포함된다.

@ImportResource

스프링 3.1에서도 몇몇 전용 태그는 XML 전용 태그로만 지원된다. 이런 빈 설정을 XML로 작성한 뒤에 @ImportResource 애노테이션을 통해 XML 설정 정보를 가져올 수 있다.

@Configuration
@ImportResource(".xml")
public class Appconfig{
}

위와 같이 애노테이션 안에 XML의 위치를 지정해준다.

@EnableTransactionManagement

@Transactional로 트랜잭션 속성을 지정할 수 잇게 해주는 AOP 관련 빈을 등록할 때 사용한다.

1.5.3 웹 애플리케이션의 새로운 IoC 컨테이너 구성

웹 환경에서는 루트 애플리케이션 컨텍스트와 서블릿 애플리케이션 컨텍스트가 존재한다. 각 컨텍스트는 web.xml의 정보를 바탕으로 생성된다.
스프링 3.1에서는 XML을 배제한 자바 코드 설정 메타정보만을 사용하기 때문에 web.xml의 설정 방법이 달라진다.

루트 애플리케이션의 컨텍스트 등록

XmlWebApplicationContext를 기반으로 애플리케이션 컨텍스트를 생성한다.
applicationContext.xml을 기반으로 루트 애플리케이션을 생성하던 것을 @Confiuration 클래스를 설정정보로 사용하도록 할 수 있다.

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

서블릿 컨텍스트 등록

서블릿 컨텍스트는 DispactherServlet 서블릿을 등록하면 생성되고, XmlWebApplicationContext가 디폴트 컨텍스트 클래스이다.

1.5.4 런타임 환경 추상화와 프로파일

스프링 빈의 메타정보는 대부분 바뀌지 않지만, 외부 리소스와 서버 환경과 연관된 애플리케이션 인프라 빈의 클래스와 속성은 실행 환경에 따라 달라질 수 있다.

환경에 따른 빈 설정정보 변경 전략과 한계

애플리케이션은 개발 환경에 따라 다른 런타임 환경으로 실행된다. 환경에 맞게 빈의 설정정보를 달라지게 하는 방법을 알아보자.

빈 설정파일의 변경

환경에 따라 다른 XML과 클래스를 이용한다.
설정 정보가 많아지면 실수의 가능성이 커진ㄴ다.

프로퍼티 파일 활용

환경에 따라 달라지는 외부 정보를 프로퍼티 파일에 두어 XML을 읽어 사용한다.
하지만 환경에 따라 빈 클래스가 아예 바뀌거나 빈 구성이 달라지는 경우는 커버하지 못한다.

런타임 환경과 프로파일

스프링 3.1 부터 새롭게 소개된 런타임 환경 추상화가 위 문제를 해결할 수 있다.
런타임 환경은 프로파일과 프러퍼티 소스로 구성되며 환경에 따라 프로파일과 프로퍼티 소스가 다르게 설정된 Environment 오브젝트가 사용된다.

환경에 따라 변하지 않는 빈은 기존 방식과 동일하게 <bean> 태그를 이용해 등록한 뒤 환경에 따라 다른 설정 정보는 profile을 지정하여 등록한다.
이를 통해 하나의 설정 파일만 이용하더라도 프로파일을 어떻게 두어 실행하냐에 따라 런타임시에 다른 설정 정보가 적용된다.

활성 프로파일 지정 방법

환경에 따라 자주 바뀌는 프로파일 파일을 따로 분리하여 관리하는 방법이다.
Environment 오브젝트에는 setActiveProfiles() 메소드가 있어 사용할 프로파일 이름을 지정할 수 있다.

활성 프로파일을 시스템 프로퍼티나 환경 변수를 통해서도 지정할 수 있다.
Dspring.profiles.active 환경변수에 프로파일을 넣어 지정할 수 있다.
-Dspring.profiles.active=dev 이와 같이 커맨드로도 지정할 수 있다.

프로파일 활용 전략

프로파일은 한 번에 두가지 이상을 활성화 할 수 있다. 따라서 환경에 따라 기능에 대한 프로파일을 지정하여 복수의 프로파일을 활성화하여 사용한다.

프로파일 적용 후에는 getEnvironment() 메소드를 통해 런타임 환경 오브젝트를 가져오 getActiveProfiles() 메소드를 실행하여 활성 프로파일 목록을 확인하는 것이 좋다.

@Configuration
@Profile("dev")

위와 같이 설정 정보에 대한 프로파일을 지정할 수 도 있다.

1.5.5 프로퍼티 소스

프로파일을 사용하는 경우에도 외부 리소스에 따라 바뀔 수 있는 정보는 빈 메타정보 외부로 독립시킬 필요가 있다.

프로퍼티

자바에서 프로퍼티란 키와 그에 대응되는 값의 쌍이다.

스프링에서 사용되는 프로퍼티의 종류

환경변수

OS의 환경변수로 자바에서는 System.getEnv() 메소드로 스프링에서는 systemEnvironment 빈으로 환경변수 프로퍼티 맵을 확인할 수 있다.

시스템 프로퍼티

JVM 레벨에 정의된 프로퍼티이다. 시스템 관련 정보(os, name, user.home)과 자바 관련 정보(java.home, java.version) 등이 있다.
-D 커맨드라인 옵션으로 프로파일을 지정할 수 있으며 System.getProperties(), systemProperties 빈으로 확인할 수 있다.

JNDI

WAS의 여러 웹 애플리케이션 중 하나의 애플리케이션에 적용되는 프로퍼티이다.

서블릿 컨텍스트 파라미터

웹 애플리케이션 레벨의 프로퍼티로 서블릿 컨텍스트 초기 파라미터를 이용한다.

서블릿 컨픽 파라미터

서블릿 컨텍스트는 웹 애플리케이션의 컨텍스트이고, 서블릿 컨픽은 개별 서블릿을 위한 설정이다. 지금까지 가장 범위가 좁은 프로퍼티이다.

프로파일의 통합과 추상화

스프링 3.1에서는 다양한 프로퍼티를 위치에 상관없이 API를 통해 가져올 수 있다.
Environment 오브젝트의 getProperty() 메소드를 통해 시스템 프로퍼티 소스와 환경변수 프로퍼티 소스를 찾을 수 있다.

이 메소드를 사용하면 지정된 이름의 프로퍼티가 어떤 프로퍼티 소스에 있던 모두 찾아 프로퍼티 값을 찾을 수 있다. 동일한 프로퍼티가 중복되었다면 프로퍼티 소스의 우선순위에 따라 값이 얻어진다.

프로퍼티 소스를 코드에서 직접 추가할 수도 있다. 또한 우선순위를 지정할 수도 있다.

프로퍼티 소스의 사용

Environment.getProperty()

Environment 오브젝트를 주입받아 메소드를 통해 프로퍼티 값을 얻는다.

PropertySourceConfigurationPlaceholder와 <context:property-placeholder>

@PropertySource와 프로퍼티 파일

@Configuration
@PropertySource("database.properties"

프로퍼티 파일을 프로퍼티 소스로 등록하여 사용한다. 프로퍼티 소스의 이름을 지정할 수도 있고, 여러개의 프로퍼티 파일을 동시에 지정할 수도 있다.

웹 환경에서 사용되는 프로퍼티 소스와 프로퍼티 소스 초기화 오브젝트

애픞리케이션 컨텍스트에 프로퍼티 소스를 추가하기 위해서는 ApplicationContextInitializer 인터페이스를 구현하여 컨텍스트 초기화 오브젝트를 만들 수 있다. 이 오브젝트를 통해 컨텍스트가 생성된 이후에 초기화를 할 수 있다.

0개의 댓글