스프링 구성 상세

김종준·2023년 2월 2일
0

스프링 구성 상세

빈 사이클 관리

IoC 컨테이너가 제공하는 주요 기능 중 하나는 생성이나 소멸 같은 빈 라이프사이클의 특정 시점에 통지받을 수 있게 빈을 생성하는 기능이다.

초기화 이후 이벤트

빈에 모든 프로퍼티 값을 설정하고 의존성 점검을 마치자마자 발생한다.

소멸 이전 이벤트

스프링이 빈 인스턴스를 소멸시키기 바로 전에 발생한다.

하지만 프로토타입 빈에는 스프링이 소멸 이전 이벤트를 통지하지 않는다.

스프링은 이러한 이벤트를 받을 수 있는 아래 세 가지 방법을 제공한다.

  • 인터페이스 기반 : InitializingBean, DisposibleBean
  • 메서드 기반 : @Bean(initMethod = " "), @Bean(destoryMethod = " ")
  • 애너테이션 기반 : @PostConstruct,@PreDestory

빈 생성 / 소멸 시점에 통지받기

생성 )

빈은 생성자에서 의존성 검사를 할 수 없다.

빈 생성 시점에는 스프링이 빈에 필요한 의존성을 공급할 수 없기 때문이다.

스프링 초기화 콜백은 의존성 제공이 완료된 이후에 호출되며 주로 사용자가 의존성 검사를 수행한다.

소멸 )

주로 스프링 소멸 콜백은 메모리에 담겨 있는 데이터를 스토리지에 기록하고 장시간 실행 중인 빈을 종료한다.

아래는 스프링이 콜백을 확인하는 순서대로 설명하겠다.

@PostConstruct / @PreDestroy 애너테이션으로

빈 생성 / 소멸 시 실행할 메서드 지정하기

이는 xml을 통해 빈생성시 실행할 메서드 지정할 때와 코드가 비슷하다.

다만 xml이 아니라 메서드에 직접 @PostConstruct / @PreDestroy 를 사용하여 스프링에게 알려준다는 차이가 있다.

InitializingBean / DisposableBean 인터페이스 구현을 통해

빈 생성 / 소멸 시 실행할 메서드 지정하기

생성 )

InitializingBean 인터페이스는 afterPropertiesSet()을 구현하여야 하고 이 메서드에 구현한 동작이 빈 생성 시 실행된다.

InitializingBean 인터페이스를 사용하면 스프링이 초기화 콜백으로 어떤 메서드를 호출해야 할지 안다.

따라서 초기화 메서드를 지정하는 추가 구성이 필요 없다.

소멸 )

DisposableBean 인터페이스는 destroy()을 구현하여야 하고 이 메서드에 구현한 동작이 빈 소멸 시 실행된다.

xml을 통해 빈 생성 시 / 소멸 시 실행할 메서드 지정하기

생성 )

빈의 메서드 하나를 지정해 초기화 콜백으로 사용하겠다고 지정하는 것이다.

이 지정은 ApplicationContext를 구성하는 xml 파일에서 지정한다.

이는 스프링이 초기화 콜백으로 어떤 메서드를 호출해야 할지 모르기 때문에 스프링에 알려주는 것이다.

Ex)

위의 예제의 경우 singerOne이라는 id를 가진 빈이 생성될 때는 init 메서드가 사용된다는 뜻이다.

그리고 이때 주의해야 할 것은 초기화 메서드는 인자를 받을 수 없다.는 것이다.

소멸 )

"destroy-method = destroy"

@Bean으로 빈 생성 / 소멸 시 실행할 메서드 지정하기

xml을 사용하지 않는다면 @Bean을 통해 동일하게 작성할 수 있다.

생성 )

@Bean(initMethod = "init") = init-method = "init"

@Lazy = default-lazy-init = true

소멸 )

@Bean(destoryMethod = "destroy") = destroy-method = "destroy"

@Lazy = default-lazy-init = true

빈 생성 과정 정리

빈 생성 시 실행할 메서드를 지정하는 방법을 알아보았으니 다시 한번 빈이 생성되는 과정을 정리해보면 다음과 같다.

  1. 빈 생성을 위해 생성자 호출
  2. 의존성 주입
  3. 빈 생성 시 실행할 메서드 실행
셧다운 후크

그리고 빈 소멸 콜백의 단점을 알아보면 자동으로 호출되지 않는다는 점이다.

ctx.destroy()와 같이 명시적으로 호출해야 한다고 한다.

이는 빈이 많이 없으면 문제가 안 되지만 많으면 문제가 된다.

이를 해결해주는 방법이 셧다운 후크이다.

AbstractApplicationContext의 destroy() 대신 registerShutdownHook() 메서드를 사용하면 된다.

빈이 스프링을 알게 하기

개발자가 의존성을 주입하게 되면 빈이 컨테이너로 주입된다.

특정 환경에서 몇 가지 이유로 빈에서 컨테이너에 접근해야 하는 경우가 있고, 이때 필요한 의존성을 의존성 주입으로 부여받으려면 빈이 컨테이너에서 어떤 이름으로 사용되는지 알아야 한다.

BeanNameAware 인터페이스 사용하기

BeanNameAware 인터페이스의 setBeanName(String)메서드를 구현하여 빈의 이름을 설정할 수 있다.

Factory Bean

스프링에서 new 연산자로 생성할 수 없는 의존성의 경우와 같이 스프링 구문으로는 생성 및 관리할 수 없는 객체를 관리하기 위한 어댑터인 FactoryBean 인터페이스를 제공한다.

FactoryBean은 다른 빈을 생성하는 팩터리 역할을 담당하는 빈이라 생각할 수 있고

new 연산자로 생성할 수 없는 경우는 정적 팩터리 클래스로 접근해야 하는 경우가 있을 수 있다.

이는 ApplicationContext에서 구성하지만, 스프링이 FacotryBean 인터페이스를 사용해 의존성 요청이나 검색 요청에 응답할 때는 일반적인 빈과 달리 FactoryBean 인스턴스를 반환하지 않는다.

그 대신 `FactoryBean.getObject() 메서드를 통해 반환받은 결과를 반환한다.

FactoryBean의 역할은 더 많은 애플리케이션 클래스를 IoC의 설정 방식으로 사용할 수 있도록 하는 인프라를 지원하는 것이다.

FactoryBean에는 직접 접근하는 것이 아니라 스프링에 맡기는 것이 좋다.

ApplicationContext

ApplicationContext의 주된 기능은 애플리케이션을 개발할 때 좀 더 풍부한 기반을 제공하는 것이라 한다.

이 ApplicationContext를 사용할 때 가장 큰 장점은 스프링과 스프링이 관리하는 리소스를 100프로 선언적인 방식으로 구성하고 관리할 수 있다는 것이라 한다.

아래는 ApplicationContext가 상속하고 있는 인터페이스의 목록이다.

public interface ApplicationContext
 extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

국제화(MessageSource)

같은 화면이라도 한국에서는 "안녕", 미국에서는 "hi"라는 응답을 제공해야 할 경우가 있다.

이러한 경우에 ApplicationContext는 아래와 같은 MessageSource 구현체를 제공한다.

  • ResourceBundleMessageSource
  • ReloadableResourceBundleMessageSource

둘은 기본적으로 동일하지만 메시지 소스 파일에서 주기적으로 메시지를 다시 읽어 들일 수 있는 차이가 있다고 한다.

ResourceBundleMessageSource가 사용하는 ResourceBundle은 기본 이름이 같은 여러 메시지 프로퍼티 파일을 읽어 동작한다고 한다.

특정 로케일을 지정해 메시지늘 검색하면 ResouceBundle이 기본 이름에 로케일 이름이 붙은 프로퍼티 파일에서 해당 메시지를 검색한다.

이를 어떻게 사용하는지 알아보기 의해 getMessage()를 알아보자.

String 인수는 프로퍼티 파일에 담긴 키로, 가져올 메시지의 키를 지정한다.

Object[] 배열 인자는 메시지 내용을 교체하는 데 사용된다.

Locale은 ResourceBundleMessageSource에게 어떤 프로퍼티 파일을 사용해야 할지를 지정한다.

애플리케이션 이벤트(ApplicationEventPublisher)

모든 빈은 ApplicationListener 인터페이스를 구현해 이벤트를 받을 수 있다.

ApplicationContext가 구성될 때 ApplicationListener 인터페이스를 구현한 빈을 자동으로 리스너로 등하기 때문이다.

이벤트 자체는 ApplicationEventPublisher.publishEvent()를 통해 발행한다.

ApplicationListener 인터페이스는 onApplicationEvent라는 메서드 하나를 정의해 위와 같이 이벤트가 발행되면 호출된다.

0개의 댓글

관련 채용 정보