본문 바로가기

Spring

[Spring] DI(Dependency Injection) 종합 실습


준비


본 글의 코드예제룰 수행하기 위해서는 이전 글의 이해와 함께 코드 예제를 수행하여야 합니다.

  1. [Spring] Spring 간단한 서비스 생성 및 테스트
  2. [Spring] DI(Dependency Injection)란?
  3. [Spring] 스프링 컨테이너(Spring Container)
  4. [Spring] 빈(Bean)
  5. [Spring] 빈 스코프(Bean Scope)
  6. [Spring] 싱글톤(Singleton)
  7. [Spring] 컴포넌트 스캔(Component Scan)

 

Spring DI 실습


MemberTest.java 수정

 

package developingman.sample_Project.member;

import developingman.sample_Project.DependencyConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MemeberTest {
    public static void main(String[] args){
        ApplicationContext ac = new AnnotationConfigApplicationContext(DependencyConfig.class);
        MemberService memberService = ac.getBean("memberService", MemberService.class);

        Member member = new Member(0L, "leenom@korean.com","LeeNom" , "010-1234-1234");
        memberService.createMember(member);

        Member currentMember = memberService.getMember(0L);

        System.out.println("회원 가입한 유저 : " + member.getName());
        System.out.println("현재 첫번째 유저 : " + currentMember.getName());

        if(member.getName().equals(currentMember.getName())) {
            System.out.println("새롭게 가입한 유저와 현재 유저가 같습니다.");
        }

        memberService.deleteMember(0L);

        if(memberService.getMember(0L) == null){
            System.out.println("회원 삭제가 정상적으로 완료 되었습니다.");
        }
    }
}
  • 기존 DependencyConfig를 직접 가져와서 주입해 주는 방식에서 new AnnotationConfigApplicationContext(DependencyConfig.class); 방식을 통해 스프링 컨테이너에 등록된 빈을 가져오는 방식으로 수정하였습니다.

 

SnackTest.java 수정

 

package developingman.sample_Project.snack;

import developingman.sample_Project.DependencyConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SnackTest {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(DependencyConfig.class);
        SnackService snackService = ac.getBean("snackService", SnackService.class);

        Snack snack = new Snack(0L, "인디언밥", "indian meal", 1500);
        snackService.createSnack(snack);

        if(snackService.getSnack(0L).getKorName().equals(snack.getKorName())){
            System.out.println(snack.getKorName() + "가 등록되었습니다.");
        }

        snackService.editSnack(0L, "인디언 밥", 3000);

        if(snackService.getSnack(0L).getPrice() == 3000){
            System.out.println(snack.getKorName()+ "의 금액이 정상적으로 변경 되었습니다.");
        }

        snackService.deleteSnack(0L);

        if(snackService.getSnack(0L) == null){
            System.out.println("정상적으로 삭제 되었습니다.");
        }
    }
}

 

MemberTest 클래스와 같이 수정하였습니다. 수정 후 결과가 올바르게 출력되는지 확인합니다.

 

 

스프링 컨테이너


  • 코드 예제에서 ApplicationContext가 스프링 컨테이너입니다.
  • 기존에 DependencyConfig를 사용해 객체를 생성하고 의존 주입을 했지만, 스프링 컨테이너를 이용한 의존 주입을 사용합니다.
  • 스프링 컨테이너는 @Configuration이 붙은 DependencyConfig를 설정 정보로 사용합니다.
    • Bean이 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록합니다.
  • 직접 자바 코드로 설정 및 등록했던 것을 스프링 컨테이너에 객체만 스프링 빈으로 등록해 주고 스프링 컨테이너에서 찾아서 사용하도록 변경된 것입니다.

 

컴포넌트 스캔


컴포넌트 스캔을 이용해서 스프링 빈을 등록해 보고 @Autowired를 사용해 보겠습니다.

  • 장점
    • 스프링 빈을 자동으로 찾아 생성해 줍니다.
    • 이전에는 직접 @Bean을 통해 설정 정보를 작성하고 의존 관계도 직접 명시하였습니다.
    • 설정 정보 자체가 없기 때문에 의존 관계 주입을 클래스 안에서 해결해 줍니다.
  • @Component 애너테이션 붙은 클래스를 찾아서 스프링 빈으로 등록해 주는 방식입니다.
  • @Configuration
    • 해당 애너테이션에는 @Component가 적용되어 있기 때문에 ComponentScan 할 때 자동으로 스프링 빈 등록이 됩니다.
    • 만약 이전 설정 파일 (DependencyConfig 등)에 @Configuration 애너테이션이 붙어 있으면 @Configuration이 설정된 파일 자체를 제거하거나 전체 주석 처리를 해야 합니다.
    • 이전 설정 파일(@Configuration이 적용된)을 노두고 싶다면 ComponentScan의 Filter를 사용할 수도 있습니다.
  •   Autowired
    • @ComponentScan & @Component만 사용했을 때 DependencyConfig에 어떤 의존 객체를 주입할지 명시해주지 않기 때문에 의존 주입이 필요한 생성자 부분에 @Autowired를 통해 의존 관계 주입이 필요합니다.

 

변경 코드

  • DependencyConfig.java

 

package developingman.sample_Project;

import developingman.sample_Project.member.MemberRepository;
import developingman.sample_Project.member.MemberService;
import developingman.sample_Project.snack.SnackRepository;
import developingman.sample_Project.snack.SnackService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class DependencyConfig {
    @Bean
    public MemberService memberService() {
        return new MemberService(new MemberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemberRepository();
    }

    @Bean
    public SnackService snackService(){
        return new SnackService(new SnackRepository());
    }
    @Bean
    public SnackRepository snackRepository() {
        return new SnackRepository();
    }
}

 

테스트

ComponentScan 방식의 DependencyConfig가 정상적으로 작동되는지 테스트해 봅니다.

sample_project패키지에 ComponentScanTest.java 클래스를 만듭니다.

 

package developingman.sample_Project;

import developingman.sample_Project.member.MemberService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class ComponentScanTest {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(DependencyConfig.class);

        MemberService memberService = ac.getBean(MemberService.class);

        System.out.println(MemberService.class.isInstance(memberService));
    }
}

 

위 코드를 실행 시 ture가 출력되는지 확인합니다.