[Spring] Bean 등록 및 생명주기

곽동현·2022년 6월 29일
0

스프링 입문하기

목록 보기
7/8
post-thumbnail

Spring Bean?

Spring Bean은 스프링 컨테이너에서 관리하는 자바 객체를 의미한다. 빈은 스프링 컨테이너에 의해 인스턴스화 되며, 인스턴스화된 빈은 getBean() 메소드를 통해 가져와서 사용할 수 있고, @Autowired 어노테이션으로 의존 객체를 주입 받을 수 있다.

의존성 주입(DI)

어떤 객체가 사용하는 의존 객체를 직접 생성하는 것이 아니라
스프링 컨테이너에서 주입을 받아 사용하는 것이다. 즉 스프링 컨테이너에서 객체 정보를 가져오는 것이라 이해하자.

A 객체가 B 객체를 이용 (A는 B에 의존한다 = B는 A에 의존성이다.)

이제 ApplicationContext(스프링 컨테이너)를 통해 빈들을 설정하고 어디에 의존성을 주입할 건지를 실습해보자. 빈을 설정하는 방식은 2가지가 있었다.

1. XML 설정 파일 통해 빈 정의

<!-- applicationContext.xml -->
<!-- xml 방식으로 빈 설정하기 -->
<bean id = "demoService"
      class ="">
    <property name="demoRepository" ref="demoRepository"/>
</bean>
...
...
<bean id = "demoRepository"
      class ="">
</bean>

이후 main class에서 ApplicationContext를 활용해서 Bean을 가져와 사용하는 것이다. (DI)

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
     String [] beanDefinitionNames = context.getBeanDefinitionNames();
    System.out.println(Arrays.toString(beanDefinitionNames));

    //Bean 단일적으로 가져오기
    DemoService demoService = (DemoService) context.getBean("demoService");
}

이 방식의 단점은 모든 빈들을 일일히 등록해야 한다는 번거로움이 있다. 이번엔 component-scan을 살펴보자.

<context:component-scan base-package="[패지키명]"/>
<!-- [ ] 패키지부터 스캔을 하여 빈으로 등록하겠다라는 의미 -->

컨테이너 생성 시점에 component-scan을 통해 전체를 스캔하여 빈으로 등록해주기 때문에 번거로움이 줄어든다.


2. 자바 설정 파일 통해 빈 정의

스캐닝을 할 때는 기본적으로 @Component 어노테이션을 사용해서 빈 등록을 한다.

  • @Component를 확장한 어노테이션을 사용해서 빈 등록 가능
    • @Service
    • @Repository
    • @Controller

  • 그럼 의존성 주입을 받기 위해서는? (빈을 사용하는 것)
    • @Autowired
    • @Inject

      @Inject는 또 다른 의존성을 필요로 한다.
      그래서 주로 @Autowired를 사용한다.

@Configuration
public class ApplicatoinConfig {
    @Bean
    public DemoRepository demoRepository() {
        return new demoRepository();
    }

    //setter를 활용한 의존성 주입
    @Bean
    public DemoService demoService() {
        DemoService demoService = new DemoService();
        //custService에 setter가 있으므로 직접 의존성 주입을 받을 수 있다.
        demoService.setDemoRepository(demoRepository());
        return DemoService;
    }

    //메서드 파라미터를 활용한 의존성 주입
    @Bean
    public DemoService demoService(DemoRepository demoRepository) {
        DemoService demoService = new DemoService();
        demoService.setDemoRepository(demoRepository);
        return demoService;
    }

    //의존성 주입을 직접하지 않고 @Autowired를 사용해서 의존성 주입을 한다.
    @Bean
    public DemoService demoService() {
        return new DemoService();

        //DemoService 내에서
        //@Autowired
        //private DemoRepository demorepository; 및 setter
        //선언 되어 있어야 함.
        //즉, @Bean을 통해 Bean으로 등록되어 있어 꺼내와서 사용 가능
    }                            
}

//ApplicationContext 활용
public static void main(String[] args) {
    //해당 클래스(ApplicationConfig)를 빈 설정 파일로 사용한다.
    ApplicationContext context = new AnnotationConfigApplicationContext(ApplicatoinConfig.class);

     String [] beanDefinitionNames = context.getBeanDefinitionNames();
    System.out.println(Arrays.toString(beanDefinitionNames)); 
    //Bean 단일적으로 가져오기
    DemoService demoService = (DemoService) context.getBean("demoService");
}

@Component는 코드 수정이 가능한 클래스를 객체로 생성하여 초기화해 빈으로 등록하고자 할 때 @Component를 사용한다. 직관적으로 구조 파악이 가능하다.
@Bean은 @Configuration을 통해 자바 설정 파일임을 명시하는 클래스 안에 작성한다. (=applicationconfig)

보통 내부적으로 코드 수정이 불가능한 라이브러리를 초기화해 빈으로 등록하고자 할 때 @Bean을 사용하는 것이다.

위 ApplicationConfig를 이용한 예제 역시 빈들을 일일히 설정, 등록해야 한다. 이번엔 componentScan을 사용해보자.

@Configuration
@ComponentScan(basePackageClasses = DemoApplication.class)
//DemoApplication은 main 객체
//해당 ComponentScan은 type safe한 방식으로 현 스프링 부트기반 가장 가까운 방법
public class ApplicationConfig {

}

XML 설정 방식에서 component-scan을 사용한 것처럼 자바 설정에서는 componentScan을 사용하면 전체를 스캔하여 빈 등록을 해주기 때문에 훨씬 편하다.

빈 생명주기

Spring을 비롯해 많은 Spring Container는 자신이 관리하는 Bean의 Life-cycle을 관리해주고 특정 시점에 Bean에게 이를 알려줄 수 있는 메커니즘을 제공한다.

기본적으로 스프링 빈은 객체 생성->의존관계 주입 과 같은 라이프 사이클을 가진다.

객체를 생성하고 의존관계 주입이 끝난 다음에야 데이터를 사용할 수 있는 준비가 완료되고 그에 따라서 초기화 작업은 url이 있는 상태, 즉 의존관계 주입이 끝난 다음에 호출해야 한다.

그러면 여기서 우리가 의존관계 주입이 끝나는 시점을 어떻게 알 수 있을까?

이 때 스프링 빈의 생명주기를 알고 콜백을 알면 유용하게 활용 가능하다.

스프링 빈의 라이프 사이클은 다음과 같이 진행된다.

스프링 컨테이너 생성 -> 스프링 빈 생성(Constructor Injection) -> 의존관계 주입(Setter Injection 및 Field Injection이 일어남) -> 초기화 콜백 사용 -> 소멸전 콜백 ->스프링 종료

여기서 중요한 부분은 콜백 부분이라고 할 수 있다.

초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출
소멸전 콜백: 빈이 소멸되기 직전에 호출

그렇다면 이 콜백은 구체적으로 어떻게 사용하면 좋을까?

스프링에서 빈 생명주기 콜백에 대한 지원은 세 가지가 제공된다. 1. 어노테이션 지정, 2. 인터페이스 구현, 3. Bean설정 시 init, destroy 메서드 지정 이 있다. 상황에 따라 알맞는 방법을 사용하면 된다.

다음 학습에서 세 가지 방법의 활용도와 빈 스코프를 알아보자.

참고

https://chung-develop.tistory.com/

profile
읽고 쓰며 생각합니다 💡

0개의 댓글