반응형

스프링으로 전환


 

AppConfig 스프링 기반으로 변경

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberRepository;
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 // 설정을 구성한다고 알려줌
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 FixDiscountPolicy();
    }

}

 

MemberApp에 스프링 컨테이너(객체 생성, 관리, 의존관계 주입) 적용

package hello.core;

import hello.core.AppConfig;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

//테스트해보는 용도
public class MemberApp {
    public static void main(String[] args) {

        //AppConfig를 통하여 주입
//        AppConfig appConfig = new AppConfig();
//       MemberService memberService = appConfig.memberService();//주입!
        //멤버서비스 구현체는 생성자로 적절한 구현체들을 받게된다.
        //즉, 멤버 서비스 구현체는 어떤 구현체를 가져올지 고민안해도 됨!
        //밑에선 memberServiceImpl를 가져오고 MemberServiceImpl 내부적으로 어떤걸 쓸지 골라야됬음!
        //MemberService memberService = new MemberServiceImpl();


        /**
         * 스프링 컨테이너 적용
         */
        //ApplicationContext를 스프링 컨테이너라 보면된다. 스프링은 모든것이 이 A.C로 부터 시작된다.
        //AppConfig로부터 구성 정보를 가져온다.
        // => 스프링이 빈들을 설정해서 스프링 컨테이너에 객체를 생성해서 갖고 있는다.
        //어노테이션 기반으로 config를 하므로 AnnotationConfigApplicationContext 사용
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        
        //getBean(메서드명, 타입)으로 가져온다.
        //MemberServiceImpl.class와 같이 구체 타입을 지정해도 되나, 구현에 의존하게 되는 꼴이 되버린다.
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
        
        Member member = new Member(1l, "memberA", Grade.VIP);


        //회원가입
        memberService.join(member);

        //가입한 멤버가 있는지 조회
        Member findMember = memberService.findMember(1L);

        //확인
        System.out.println("new member = " + member.getName());
        System.out.println("findMember = " + findMember.getName());


    }
}

 

OrderApp에도 스프링 컨테이너를 적용시킨다.

package hello.core;

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

//주문 하기
public class OrderApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();
//        OrderService orderService = appConfig.orderService(); //주입!!\
//        MemberService memberService = appConfig.memberService();

        //스프링 컨테이너 생성
        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", 10000);

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



}

 

 

실행 후 로그를 보면

17:06:34.789 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberService'
17:06:34.808 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'memberRepository'
17:06:34.810 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderService'
17:06:34.811 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'discountPolicy'

"Creating shared instance of singleton bean" 스프링에 등록된 것을 알 수 있다.

스프링에 등록시 (key(메서드명), value(타입))으로 저장이된다.

 

이걸 정리하면

  • ApplicationContext = 스프링 컨테이너 (Context = 문맥)
  • 기존엔 개발자가 AppConfig를 사용해서 직접 객체 생성하고 DI
  • @Configuration 어노테이션이 붙은 AppConfig를 설정정보로 사용한다.
  • @Bean 이 붙은 메서드를 모두 호출하고 반환된 객체를 스프링 컨테이너에 등록한다. (등록된 객체 = 스프링 빈)
  • 관례로 @Bean이 붙은 메서드 명을 스프링 빈 이름으로 사용한다. (@Bean (name = "AA")와 같이 변경도 가능한데 왠만하면 관례따르는게 보기 편하고 관리 편하다.)
  • 기존엔 직접 필요한 객체를 AppConfig를 이용해서 조회했다.
  • => 스프링 컨테이너를 통해서 applicaionContext.getBean()메서드를 사용해서 스프링빈, 즉 객체를 찾게되었따.

즉, 직접 자바코드로 모든 것을 하다가

  1. 스프링 컨테이너에 객체를 스프링 빈으로 등록
  2. 스프링 컨테이너에서 스프링 빈을 찾아서 사용

과 같이 바뀌게 되었다.

 

이렇게 바꾸었을 때 장점은 무엇일까?..... => 뒤에서

 

 

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


스프링 컨테이너 생성과정을 다시 보면

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

ApplicationContext 이 스프링 컨테이너이고, 인터페이스이다.

따라서 다형성이 적용된다.

"new AnnotationConfigApplicationContext(AppConfig.class);"클래스는 ApplicationContext 인터페이스의 구현체이다.

스프링 컨테이너는 어노테이션 기반의 자바 설정 클래스로 만들수도 있고, XML을 기반으로 만들 수도 있다.

 

정리하면

  1. 스프링 컨테이너 생성

    스프링 컨테이너 생성(AppConfig.class) - 스프링 컨테이너 생성시 구성정보 지정해주어야함.

     

  2. 스프링 빈 등록

    파라미터로 넘어온 설정정보(AppConfig.class)를 사용해서 @Bean들을 다 등록함.

    빈 이름(Key) : 빈 객체(value) 로 저장된다. (빈이름은 메서드명이 사용된다.)

    ex) memberService : MemberServiceImpl@0x1

     

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

    빈들이 스프링 컨테이너에 등록이 되었지만 서로 연결되진 않았다. = 의존관계 주입이 안되었음

     

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

    각 객체들이 생성되면서 의존관계가 주입되어진다.

    동적 의존 관계 연결시켜줌.

    (설정 정보를 참고해서 의존관계가 주입되어짐.)

 

** 스프링은 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져있다.

위와같이 자바코드로 스프링 빈 등록시, 생성자를 호출하면서 의존관계 주입도 한번에 처리된다.

    @Bean//스프링 빈으로 등록
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    } // -> 호출되면서 memberservice와 리포지토리가 자동으로 연결되게 된다

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    //주문 서비스는 저장소와 할인정책이 필요하다.
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    } // 호출되면서 리포지토리, 할인정책이 불려오면서 같이 연결되게 된다.

    @Bean
    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }

이제 컨테이너에 잘 등록되었는지 확인 해보자.

728x90
반응형
블로그 이미지

아상관없어

,