스프링 프레임워크(Spring Framework) 톺아보기 - 빈(Bean)

Janek·2023년 1월 31일
0

Spring 톺아보기

목록 보기
5/10
post-thumbnail
post-custom-banner

해당 포스팅은 인프런에서 제공하는 김영한 님의 '스프링 핵심원리 기본편'을 수강한 후 정리한 글입니다. 유료 강의를 정리한 내용이기에 제공되는 예제나 몇몇 내용들은 제외하였고, 정리한 내용을 바탕으로 글 작성자인 저의 언어로 다시 작성한 글이기에 서술이 부족하거나 잘못된 내용이 있을 수 있습니다. 그렇기에 해당 글은 개념에 대한 참고 정도만 해주시고, 강의를 통해 학습하시기를 추천합니다.

빈 생명주기 콜백

DB 커넥션 풀, 네트워크 소켓과 같이 어플리케이션 시작 시점에 필요한 연결을 미리 만들고, 어플리케이션 종료시 모두 종료하려면 객체의 초기화와 종료 작업이 필요하다.

스프링 프레임워크에서 스프링 빈은 객체 생성의존관계를 주입하는 라이프사이클을 가진다. 즉 객체가 생성되고 의존관계 주입이 끝난 다음에 데이터를 사용할 수 있으며, 정상적인 초기화 작업이 가능하다. 그렇기에 스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해 초기화 시점을 알려주는 다양한 기능을 제공한다. 또한 스프링 컨테이너 종료 직전에 소멸 콜백을 주어 안전한 종료 작업을 가능하게 해준다.

이러한 스프링 빈의 이벤트 라이프사이클을 정리하면 다음과 같다.

스프링은 InitializingBean, DisposableBean 인터페이스, 설정 정보에 초기화 메서드 및 종료 메서드 지정, @PostConstruct, @PreDestroy 어노테이션 지원이라는 세가지 방법으로 빈 생명주기 콜백을 지원한다.

객체의 생성과 초기화 분리

생성자는 필수 정보(파라미터)를 받고, 메모리에 할당해 객체를 생성하는 책임을 가진다. 반면 초기화는 생성된 값들을 활용하여 무거운 동작을 수행하기 때문에 생성자 안에서 무거운 초기화 작업을 함께 처리하는 것 보다 생성과 초기화를 명확히 나누는 것이 유지/보수 관점에서 좋다.

InitializingBean, DisposableBean 인터페이스

InitializingBean 인터페이스의 afterPropertiesSet() 메서드로 초기화를 지원하며, DisposableBean 인터페이스의 destroy() 메서드로 소멸을 지원한다.

스프링 전용 인터페이스에 의존하며, 초기화 및 소멸 메서드의 이름을 변경할 수 없고 직접 고쳐서 사용할 수 없는 외부 라이브러리에 적용할 수 없다는 단점들이 존재한다. 스프링 초기에 사용된 방법이며, 현재는 거의 사용되어지지 않는다.

빈 등록 초기화, 소멸 메서드 지정

설정 정보에 @Bean(initMethod = "init", destroyMethod = "close")와 같이 초기화 및 소멸 메서드를 지정할 수 있다.

메서드 이름을 자유롭게 지정할 수 있으며, 스프링 빈이 스프링 코드에 의존하지 않는다. 또한 코드가 아닌 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메서드를 사용할 수 있다.

소멸 메서드 추론

@BeandestroyMethod 속성은 기본 값이 (inferred) 즉 추론으로 등록되어 있다. 대부분의 라이브러리는 소멸 메서드의 이름을 closeshutdown으로 사용하기에 소멸 메서드를 따로 등록하지 않아도 이러한 이름의 메서드를 자동으로 호출해준다. 해당 기능을 사용하지 않으려면 destroyMethod=""와 같이 빈 공백으로 지정하면 된다.

@PostConstruct, @PreDestroy 어노테이션

최신 스프링에서 가장 권장하는 방법으로, @PostConstruct, @PreDestroy 어노테이션을 사용하면 편리하게 초기화와 종료를 실행할 수 있다. 스프링에 종속적인 기술이 아닌 자바 표준이기 때문에 다른 컨테이너에서도 동작한다. 단 외부 라이브러리에는 적용하지 못한다는 단점이 있기에, 라이브러리에서 초기화/종료가 필요할 경우 @Bean의 기능을 사용해야 한다.

빈 스코프

빈 스코프란 말 그대로 빈이 존재할 수 있는 범위를 뜻하며, 스프링은 기본적으로 싱글톤 스코프, 즉 하나의 빈으로 스프링 컨테이너가 종료될 때 까지 유지하는 전략을 가진다.

스프링은 싱글톤 스코프와 함께 빈의 생성과 의존관계 주입까지만 관여하는 프로토타입 스코프와 requset(웹 요청 부터 그에대한 응답까지 유지), session(웹 세션의 생성 부터 종료까지 유지), application(웹의 서블릿 컨텍스트와 같은 범위로 유지) 등의 웹 관련 스코프 또한 지원한다. 빈 스코프는 다음과 같이 지정할 수 있다.

컴포넌트 스캔 자동 등록

@Scope("prototype")
@Component
public class TestBean {}

수동 등록

@Scope("prototype")
@Bean
public class TestBean() {
	return new TestBean();
}

프로토타입 스코프

어떤 클라이언트에서 요청하든지 항상 같은 인스턴스의 스프링 빈을 반환하는 싱글톤 스코프의 빈과 달리 프로토타입 스코프의 빈은 항상 새로운 인스턴스를 생성하고 의존관계를 주입, 초기화까지 해서 반환한다.

프로토타입 스코프의 빈은 스프링 컨테이너가 생성 부터 초기화 까지만 관여하기 때문에 스프링 컨테이너 종료시 소멸 메서드가 실행되지 않는다. 그렇기 때문에 프로토타입 빈을 조회한 클라이언트가 관리해야 하며, 소멸 메서드에 대한 호출도 클라이언트가 직접 해야한다.

그러나 스프링의 일반적인 싱글톤 빈이 프로토타입 빈을 의존할 경우 주입 받은 싱글톤 빈에서 해당 프로토타입 빈이 계속 유지된다. 이를 해결하기 위해서는 싱글톤 빈이 프로토타입 빈을 사용할 때 마다 ApplicationContext를 사용하거나 ObjectProvidergetObject()를 사용하여 스프링 컨테이너에 새로 요청하여 사용하면 된다. 또한 자바 표준으로javax.inject:javax.inject:1 라이브러리의 Provider를 사용해 스프링에 종속적이지 않게 구현할 수 도 있다.

웹 스코프

웹 스코프는 웹 환경에서만 동작하며, 스프링이 해당 스코프의 종료시점까지 관리하기 때문에 종료 메서드가 호출된다. 웹 스코프의 종류는 다음과 같다.

  • request : HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프로 각각의 요청에 대한 별도의 빈 인스턴스가 생성되고, 관리된다.
  • session : HTTP Session과 동일한 생명주기를 가지는 스코프다.
  • application : 서블릿 컨텍스트(ServletContext)와 동일한 생명주기를 가지는 스코프다.
  • websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프다.

request 스코프

request 스코프를 사용하면 각각의 HTTP 요청에 대한 로깅 등 구분된 작업을 수행할 수 있다. 그러나 해당 스코프는 클라이언트의 요청이 오기 전까지 빈이 생성되지 않으므로 어플리케이션 실행시 오류가 발생한다. 따라서 ObjectProvider 등을 사용하여 빈의 생성을 지연시켜 사용하거나 @ScopeproxyMode=ScopedProxyMode.TARGET_CLASS 속성을 사용하여 프록시 객체를 미리 주입하여 사용할 수 있다.

profile
만들고 나누며, 세상을 이롭게 하고 싶습니다.
post-custom-banner

0개의 댓글