인프런/스프링핵심원리(기본)

★★10) 스프링으로 전환하기, ApplicationContext ,@Configuration,@Bean , 스프링 컨테이너, 스프링 빈 , 스프링컨테이너 생성과정

backend dev 2022. 12. 15.

AppConfig.java 수정

@Configuration을 클래스 앞에 붙여서 앱의 구성정보,설정정보 파일임을 명시해준다. 

@Bean 어노테이션을 각 메서드에 붙여준다. -> 각 객체들이 스프링컨테이너에 등록된다.

@Configuration
public class AppConfig { //프로젝트의 객체 생성,구성,주입 환경설정을 하는 중요 역할

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(MemberRepository());
    }
    @Bean
    public MemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(MemberRepository(), DiscountPolicy());
    }
    @Bean
    public DiscountPolicy DiscountPolicy() {
        return new RateDiscountPolicy();
    }

}

다음과 같이 수정하였다.

 

MemberApp.java 수정

ApplicationContext가 스프링 컨테이너라고 보면 된다. ( Bean 객체들을 관리함)

 

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

이 코드를 추가해준다. 

AppConfig에 적은 @Bean 어노테이션이 붙은 객체들을 생성해서 스프링 컨테이너에 등록시켜준다.

 

public class MemberApp {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        
        MemberService memberService = applicationContext.getBean("memberService",
            MemberService.class);//객체의 이름은 AppConfig에 적은 메서드이름으로 적어준다. 두번쨰는 타입을 적어준다.

        Member memberA = new Member(1L, "memberA", Grade.VIP); //테스트용 멤버생성
        memberService.join(memberA); //가입메소드 사용

        Member findMember = memberService.findMember(1L); // 정상 가입됬는지 findMember 메소드를 사용해본다.
        System.out.println("new member = " + memberA.getName());
        System.out.println("find Member = " + findMember.getName());
    }

}

스프링빈으로 등록된 멤버서비스를 컨테이너에서 가져올때 Context를 이용해서 getBean으로 가져온다.

가져올 객체이름(AppConfig에 적은 메소드명) 과 타입을 적어서 가져올 수 있다.

 

MemberApp을 실행해보면

결과위에 로그가 찍힌것을 확인할 수있는데 빨간부분이 AppConfig 파일(@Configuration)과  @Bean 으로 등록해놓은것들이 컨테이너에 들어간것을 확인할 수 있다.  빨간색 윗부분은 스프링이 필요해서 기본적으로 등록시켜놓는 Bean이다.

 

 

OrderApp.java 도 수정

public class OrderApp {

    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();
//        OrderService orderService = appConfig.orderService();
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        OrderService orderService = ac.getBean("orderService", OrderService.class);

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

        Order order = orderService.createOrder(memberId, "itemA", 10000);
        System.out.println("order = " + order);
    }

}

Context를 이용해서 컨테이너에 있는 빈을 꺼내오는 형식으로 수정하였다.

잘 동작하는것을 확인할 수 있다.

 

 

ApplicationContext

 

 

이전에는 AppConfig 객체를 만들고 AppConfig 안에있는 메소드를 이용하여 객체를 생성하고 그 객체를 주입해주었지만

이제 부터는 스프링컨테이너를 사용하여 필요한 스프링 빈(객체)를 가져온다. 

 

스프링컨테이너는 @Configuration 어노테이션으로 AppConfig를 설정(구성)정보로 사용하고 , AppConfig안에 @Bean 어노테이션이 붙은 메소드들을 호출해서 반환된 객체를 스프링 컨테이너에 등록된다.

스프링컨테이너에 등록된 객체는 스프링빈이라 한다.

 

스프링빈은 @Bean이 붙은 메소드명을 스프링 빈의 이름으로 사용한다. ( 물론 @Bean(name = "바꾸고싶은이름") 식으로 바꿀 수 있다 , 디폴트값을 사용하는것이 좋긴하다) 

 

기존에는 개발자가 직접 자바코드로 모든것을 했다면 이제부터는 스프링 컨테이너에 객체를 스프링 빈으로 등록하고, 

스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 변경되었다.

 

 


스프링 컨테이너와 스프링 빈

 

스프링 컨테이너 생성

스프링 컨테이너가 생성되는 과정을 알아보자.

ApplicationContext applicationContext =new AnnotationConfigApplicationContext(AppConfig.class);

ApplicationContext를 스프링 컨테이너라고 한다. 

ApplicationContext는 인터페이스이고 그걸 구현한 구현체 중 하나가 AnnotationConfigApplicationContext이다.

 

스프링 컨테이너는 XML 기반으로 만들수도 있고,

어노테이션 기반의 자바 설정 클래스로도 만들 수 있다.

이전에 만든 AppConfig.java에서 사용했던 방식이

어노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든것이다.

@Configuration
public class AppConfig { //프로젝트의 객체 생성,구성,주입 환경설정을 하는 중요 역할

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(MemberRepository());
    }
    @Bean
    public MemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(MemberRepository(), DiscountPolicy());
    }
    @Bean
    public DiscountPolicy DiscountPolicy() {
        return new RateDiscountPolicy();
    }

}

위에 코드가

어노테이션 기반(@Configuration,@Bean)의 자바 설정 클래스(AppConfig.class)이고

 

ApplicationContext applicationContext =new AnnotationConfigApplicationContext(AppConfig.class);

위의 코드가 어노테이션기반 자바설정 클래스 AppConfig.class를 가지고

스프링컨테이너를 생성하는 코드이다.

 

 

스프링 컨테이너의 생성 과정

1. 스프링 컨테이너의 생성

- new AnnotationConfigApplicationContext(AppConfig.class) 라는 코드가 실행되면서 스프링 컨테이너가 생성된다.

- 스프링 컨테이너 안에는 스프링 빈 저장소라는게 있다. 그 안에 key : 빈 이름 value : 빈 객체로 저장이 되는.

- 그리고 그안에 스프링빈을 채우기 위해서 구성정보를 활용해줘야하는데 그때 전달된 AppConfig.class를 이용하는것이다

 

2. 스프링 빈 등록

@Bean 어노테이션 붙은 메소드들을 전부 호출해서

메소드이름을 빈이름(key)로 가지고 그 메소드의 리턴값은 빈 객체(value)로 가진다.

아무튼 빈 이름은 중복이 되면 안된다.

 

3. 스프링 빈 의존관계 설정 - 준비

스프링빈간에 의존관계 설정을 해야한다.

4. 스프링 빈 의존관계 설정 - 완료

설정정보(AppConfig.java)를 통해 의존관계를 주입해준다.

memberService() 메소드를 보면 멤버서비스임플 객체를 생성하면서 전달인자로 memberRepository를 전달한다.

그렇다는것은 멤버서비스 객체를 생성하려면 멤버리포지토리가 필요한것이므로 

멤버서비스는 멤버리포지토리를 의존한다고 볼 수 있다 ( 멤버서비스가 멤버리포지토리를 가리키는 의존관계)

 

오더서비스는 멤버리포지토리와 디스카운트폴리시 둘다 의존하므로 오른쪽 그림같이 표현한다.

위에 AppConfig를 보면 알 수 있듯이 스프링빈 생성하면서 자동으로 의존관계도 주입된다.

 

댓글