스프링 [Spirng] 빈 생명주기 (빈 라이프사이클, 빈 범위)란

반응형

빈 객체의 라이프사이클(웹을 다만들고나서 이후에 추가를더 하고싶을때 보통 사용함.)

  • 생성, 할당, 초기화, 사용, 소멸의 과정을 관리한다.
    • 스프링 컨테이너는 두 가지 방식을 이용해서 빈의 라이프사이클을 관리할 수 있다.
    • 스프링이 제공하는 특정 인터페이스를 상속받아 빈을 구현한다.
    • 스프링 설정에서 특정 메서드를 호출하라고 지정한다.

빈 라이프사이클 개요

  • 스프링 컨테이너는 빈 객체를 생성하고 초기화하고 소멸할 때 아래 순서로 빈 객체의 메서드를 실행한다.

개요

  • 빈의 초기화와 소멸 방법은 각각 세 가지가 존재한다. 각 방식이 한쌍을 이루어 함께 사용되곤한다.
  • PostConstruce메서드로 초기화, PreDestroy메서드로 소멸
    InitializingBean.afterPropertiesSet()메서드로 초기화 DisposableBean.destroy() 메서드로 소멸
    커스텀 init 메서드로 초기화 커스텀 destroy메서드로 소멸
  • 해당 초기화/소멸 과정이 필요한 전형적인 예시로 데이터베이스 커넥션 풀 기능이다.
  • 커넥션 풀은 미리 커넥션을 생성해 두고 커넥션이 필요할 때 제공하는 기능이며, 초기화 과정을 필요로 한다. 이후 필요 없어지게 되면 생성한 커넥션을 닫기 위한 소멸 과정을 필요로 한다.
  • 커넥션 풀 기능을 스프링 빈으로 사용하고 싶을경우 InitializingBean과 DisposableBean을 상속받아서 초기화, 소멸과정을 처리한다!!!111 CE

클래스를 빈으로 등록후 스프링 컨테이너는 빈 생성 후 afterPropertiesSet()메서드를 호출해서 초기화를 진행하고 destroy()메서드를 호출해서 소멸을 진행한다.(나중에 작업해서 구현할때 해당 클래스에 객체가 생성되서 등록이 될때 초기화 작업을 하고싶을때 사용하면되고 안할꺼면 안해도 된다)

객체를 생성만 했을때 라이프사이클이 어떻게 동작하는지.

xml.

두 인터페이스를 모두 상속해야 하는 것은 아니고, 필요한 인터페이스만 상속받으면 된다. 스프링 컨테이너가 빈 객체를 생설할 때 초기화만 필요하다면 InitializingBean 인터페이스만 상속 받아 구현하면 된다.

초기화만 구현 받을시 :

초기화와 소멸 구현 받을시 :

두개를 구현해서 오버라이드를 하는것보단 어노텐션을 이용해서 사용하는것이 편하긴하다.

@PostConstruct(초기화) @PreDestroy(소멸) - 메소드이름은 어느걸쓰던 사용자마음.

혹은 init, destroy예(xml경로잡을때)

<bean class="000" init-method="init" destroy-method="destroy"/>

ApplicationContextAware 인터페이스와 BeanNameAware 인터페이스

  • 빈으로 사용될 객체에서 스프링 컨테이너에 접근해야하거나, 빈 객체에서 로그를 기록할 때 빈의 이름을 남기고자한다면.( 스프링 컨테이너가 있고, 객체가 생성되어있을때 해당 객체가 포함된 스프링 컨테이너에 접근하고싶다는것 내 스프링 컨테이너에 접근하고싶으나 어떻게 접근해야하는지 this와 비슷. )(스프링컨테이너에 빈설정되서 들어간다, 빈 내부에서 자기자신에 스프링컨테이너에 접근해 작업하고싶을때 어떻게하는지) (DI설정 안하고 같은 컨테이너에 다른 객체를 가져다쓸때, 코드를 억지로 만들어 쓴다 많이 안쓴단다.)
    • o.s.context.ApplicationContextAware
      이 인터페이스를 상속받은 빈 객체는 초기화 과정에서 컨테이너(ApplicationContext)를 전달받는다.
    • o.s.beans.factory.BeanNameAware
      이 인터페이스를 상속받은 빈 객체는 초기화 과정에서 빈 이름을 전달받는다.

ApplicationContext 인터페이스를 상속받아 구현한 클래스는 setApplicationContext()메서드를 통해 컨테이너 객체(ApplicationContext)를 전달 받는다. 전달 받은 컨테이너를 필드에 보관한 후, 이를 이용해서 다른 빈 객체를 구하거나 컨테이너가 제공하는 기능(이벤트, 메시지)등을 사용할 수 있다.

예시.

public class WorkScheduler implements ApplicationContextAware{ // 워크스케줄러 클래스 내부에서 자기자신에 스프링 컨테이너에 접근해 작업하고싶다. ApplicationContextAware 를 임포트(구현한다)  

private WorkRunner workRunner;  
private ApplicationContext ctx;  


@Override  
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{  
this.ctx = applicationContext;  
} // ApplicationContextAware이 가지고있는 setApplicationContextAware를 오버라이드한다  

public void makeAndRunWork(){  
for(long order = 1; order <=10; order++){  
Work work = ctx.getBean("workProto", Work.class); // 자기자신에 스프링컨테이너에 접근해 다른 빈 객체를 꺼낸다.  
}  
}

BeanNameAware인터페이스

예시.

public interface BeanNameAware extends Aware{  
void setBeanName(String name);  
}

BeanNameAware인터페이스를 상속받아 구현한 클래스는 setBeanName()메서드를 이용해서 빈의 이름을 전달 받는다.

로그 메시지에 빈에 이름을 함께 기록해야 할 때처럼 빈의 이름이 필요한 경우 BeanNameAware인터페이스를 사용하면된다.

  • 주로 같은 타입을 가진 빈 객체들이 두 개 이상 존재하고, 각각 빈의 이름으로 구분해야할 때, BeanNameAware인터페이스를 사용한다.

빈 객체 범위

  • 스프링의 빈은 범위(scope)를 갖는데, 주요 범위는 두가지로 나뉜다.
    • 싱글톤(singleton)범위
    • 프로토타입(prototype)범위

싱글톤 범위

별도 설정을 하지 않을 경우 스프링은 빈 객체를 한 번만 생성하게 된다.

getBean()메서드를 두 번 이상 호출해서 빈을 구하면 매번 동일한 빈 객체를 리턴하게 된다.

예시.

<bean id="pool1" class="net.madvirus.chap03.ConnPool1" />

스프링컨테이너에 있는것 한개를 수십, 수백명이 붙어서 작업을한다.(싱글톤 하나 만들어두고 돌려쓰자)

XML 설정을 통해서 컨테이너를 생성한 뒤, 다음에 pool1빈 객체를 만들어주고

예시.

ConnPool1 p1 = ctx.getBean("pool1", ConnPool1.class);  
ConnPool1 p2 = ctx.getBean("pool1", ConnPool1.class);  

p1 == p2는 동일하다, 즉 동일한 객체를 참조해버린다.

스프링 컨테이너는 이름이 pool1인 빈 객체를 한 개만 생성하고, getBean()메서드는 매번 동일한 객체를 리턴하기 때문에 p1과 p2는 동일한 객체를 참조하게 되버린다.

스프링 컨테이너가 초기화되고 종료되기 직전까지 빈 객체는 한 개만 생성되는데 스프링 컨테이너를 기준으로 이들 빈 객체는 한 개만 존재하므로해당 빈은 싱글톤(singleton)범위를 갖는다.

스프링은 싱글톤을 기본 값으로 갖고있기에 별도로 설정을 하지 않을경우 빈은 싱글톤을 갖게된다

싱글톤 범위라는 것을 명시적으로 표시하려면 Scope속성이나 @Scope 어노텐션을 추가해주면 된다.

예시. XML

<bean id="pool1" class="net.madvirus.chap03.ConnPool1"  scope="singleton"  />

예시. JAVA

....  
@Bean  
**@Scope("singleton")**  
pbulic ConnPool1 pool1(){  
return new ConnPool1();  
}

프로토타입 범위

for루프에서 매번 Work객체를 생성

매번 생성되는 Work 객체는 order 프로퍼티를 제외한 나머지가 동일한 값을 갖고 있는다.

동일한 값을 갖는 객체를 생성할 때 사용할 수 있는 것이 프로토타입 범위를 갖는 빈이다.

프로토타입(prototype)범위의 빈은 객체의 원형으로 사용되는 빈으로서, 프로토타입 범위 빈을 getBean()등을 이용해서 구할 경우 스프링 컨테이너는 매번 새로운 객체를 생성해버린다.

프로토타입 범위로 설정하기 위해서는 <bean> 태그의 scope 속성을 prototype로 지정하면 된다.

자바 설정을 사용한다면 @Bean 어노텐션을가진 메서드에 @Scope 어노텐션을 적용해서 범위 값을 지정해주면 된다.

프로토타입 범위를 가진 빈을 찾을 경우, 스프링은 매번 새로운 객체를 생성해서 리턴한다.

work1, work2, work3은 모두 다른 객체가 된다.

반응형