본문 바로가기

Spring

Spring- 스프링 컨테이너로 등록하기(1)

스프링 컨테이너로 등록하기

@Configuration

 설정 클래스를 스프링 빈으로 등록하기 위해서는 @Configuraition 어노테이션을 붙여준다. 이번에도 AppConfig 클래스를 예시로 들겠다.

 

AppConfig 클래스(DI 컨테이너)

package hello.core;

@Configuration // @Configuration : 설정 정보
public class AppConfig {
   .....
}

@Bean

 사실 AppConfig는 다음과 같이 구현되어 있다.

 

AppConfig 클래스(DI 컨테이너) 내부 모습

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // @Configuration : 설정 정보
public class AppConfig {

    @Bean  // @Bean : 스프링 컨테이너 등록
    public MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public DiscountPolicy discountPolicy(){
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }
    @Bean
    public MemberService memberService(){
        //생성자 주입
        return new MemberServiceImpl(memberRepository());
    }
    @Bean
    public OrderService orderService(){
        //생성자 주입
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }
}

 AppConfig를 보면 메소드에 @Bean 어노테이션이 존재한다.

 

  @Bean은 해당 메소드를 수동으로 스프링 컨테이너에 빈으로 등록하는 어노테이션이다. 수동으로 빈을 등록할 때에는 메소드 이름으로 빈이 등록되므로 동일한 이름의 메소드를 등록하지 않도록 주의 해야한다.

 

  스프링 컨테이너는 @Configuration 어노테이션이 붙은 클래스를 찾아서 자동으로 빈으로 등록해주고, 또한 해당 클래스를 파싱하여 @Bean이 붙은 메소드의 빈을 생성한다. @Bean을 사용하는 클래스에는 반드시 @Configuration 어노테이션을 활용하여 해당 클래스에서 Bean을 등록하고자 함을 명시해주어야 한다. 이는 싱글톤을 보장하기 위해서이다.

 

 

스프링 컨테이너 정리

기존의 OrderApp 클래스(클라이언트 클래스)

package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class OrderApp {
    public static void main(String[] args) {
        AppConfig appConfig = new AppConfig();
        MemberService memberService = appConfig.memberService();
        OrderService orderService = appConfig.orderService();

        Long memberId = 1L;
        Member member = new Member(memberId, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, "itemA", 20000);

        System.out.println("order= " + order);
    }
}

  기존의 방식대로라면 위처럼 DI 컨테이너인 직접 AppConfig 클래스 객체를 생성해서 의존관계 주입을 담당하고 사용했다. 이는 실제로 OCP, DIP를 충족할 수 있는 훌륭한 방법이었다.

  다만 이는 스프링 컨테이너를 사용하지 않은 순수 자바 코드만을 이용한 방식이고, 위에서 @Configuration, @Bean과 같이 스프링 빈으로 등록할 수 있는 방법을 배웠으니 스프링 컨테이너를 통해서 위의 코드를 구현할 수 있다.

 

스프링 컨테이너를 이용한 OrderApp 클래스(DI 컨테이너)

package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class OrderApp {
    public static void main(String[] args) {
        
        ApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
        
        MemberService memberService = 
                applicationContext.getBean("memberService", MemberService.class);        
        OrderService orderService = 
                applicationContext.getBean("orderService",OrderService.class)
                
        Long memberId = 1L;
        Member member = new Member(memberId, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, "itemA", 20000);

        System.out.println("order= " + order);
    }
}

  16~22번 라인이 좀 바뀐 것을 볼 수 있다. 여기만 보자.

 

 "ApplicationContext"를 스프링 컨테이너라고 한다. 또한 ApplicationContext는 인터페이스이다 기존에는 개발자가 AppConfig를 사용해서 직접 객체를 생성하고 DI를 했지만, 이젠 스프링 컨테이너를 통해서 사용을 한다.

 스프링 컨테이너는 @Configuration이 붙은 AppConfig를 설정(구성)정보로 사용한다. 여기서 @Bean이라고 적힌 메소드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체스프링 빈이라고 한다.

 

  요약

  • @Configuration으로 DI 컨테이너를 스프링에 설정 정보로 등록
  • @Bean 메소드에서 반환된 객체를 스프링 빈으로 등록
  • 스프링 컨테이너에 등록된 객체를 스프링 빈이라고 함  

 이전에는 AppConfig를 사용해서 필요한 객체를 직접 조회했지만 이제는 스프링 컨테이너를 통해서 필요한 스프링 빈을 찾아야 한다. 스프링 빈은 applicationContext.getBean("조회 메소드명", 반환형)을 통해서 찾을 수 있다. (참고로 applicaitonContext는 위 소스코드에 나와있는 ApplicationContext 객체이다)