본문 바로가기

Spring

[Spring] DI(Dependency Injection)란?

 

DI(Dependency Injection)란?


DI는 의존성 주입으로써 스프링 원칙 중 하나인 IoC(Inversion of Control)를 구현하기 위해 사용되는 방법 중 하나입니다.

앞서 작성한 간단한 서비스 생성 및 테스트 글에서 작성한 예제 코드를 살펴보도록 하겠습니다.

 

 

 

위 작성된 코드는 MemberRepository 객체에 의존성을 가지고 있습니다.

클래스에 구현된 세 메서드는 전부 MemberRepository 클래스로 구현한 객체를 통해 메서드를 사용하고 있습니다.

이러한 상황에서 MemberRepository라는 객체를 다른 MockRepository라는 객체로 교체해야 한다면 어떻게 해야 할까요?

private final MemberRepository memberRepository = new MemberRepository();
-->
private final MemberRepository memberRepository = new MockRepository();

위와 같은 방식으로 교체한다면 새롭게 의존 관계를 만든 MockRepository를 새롭게 작성하여야만 합니다.

 

만약 위와 같이 객체 간의 관계가 변경될 때마다 직접 해당 코드를 찾아 수정하고 문제점이 없는지 살펴보는 과정을 수행하여야만 하지만, 우리는 DI를 통해 위와 같은 문제를 해결할 수 있습니다.

 

 

 

위 코드와 같이 생성자를 통해 의존성을 주입받음으로써 우리는 객체가 생성되는 순간 의존관계를 설정할 수 있습니다.

 

생성자뿐 아니라 다른 방식으로도 의존성 주입이 가능하지만, 일반적으로는 생성자를 통한 의존 관계 주입을 사용합니다.

 

생성자를 통해 의존성을 주입하게 되면, 실제로 스프링에서 의존성 주입을 도와주게 됩니다. 이 방법은 스프링에서 공식적으로 추천하는 방법입니다.

 

위와 같이 코드를 수정하면 기존에 작성했던 Test 파일에서 MemberService 객체를 생성할 때 오류가 발생합니다.

오류 발생의 해결 방법으로는, 의존성 주입을 관리하는 설정 파일을 만들어 관심사 분리를 통해 해결할 수 있습니다.

 

해결방법


 

memberService와 같이 snackService 객체도 생성자 주입을 통한 코드로 변경 후, 새로운 파일을 생성합니다.

이후 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;

public class DependencyConfig {
    public MemberService memberService() {
        return new MemberService(new MemberRepository());
    }
    public MemberRepository memberRepository() {
        return new MemberRepository();
    }

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

 

이렇게 역할을 나누어 작성해 준다면 더 이상 서비스 내부에서 객체 주입 관련해서 수정 코드가 발생하는 것이 아닌 DependencyConfig.java 에서 구현 부분만 수정해 주면 됩니다.

 

  • MemberService와 SnackService 입장에서는 생성자를 통해 어떤 구현 객체가 주입될지 알 수 없으며, 알 필요도 없습니다.
    • 어떤 객체가 주입될지 외부(DependencyConfig)에서 결정합니다.
  • MemberService와 SnackService는 오로지 실행에만 집중하게 됩니다.
  • 해당 코드의 수정이 모두 이루어지면 실습에서 진행했던 MemberTest.java와 SnackTest.java에서 서비스 객체를 생성하는 부분에서 오류를 확인할 수 있습니다.
  • 위 오류는 코드의 수정이 필요합니다 

 

MemberTest.java 코드

 

package developingman.sample_Project.member;

import developingman.sample_Project.DependencyConfig;

public class MemeberTest {
    public static void main(String[] args){
        DependencyConfig dependencyConfig = new DependencyConfig();
        MemberService memberService = dependencyConfig.memberService();

        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("회원 삭제가 정상적으로 완료 되었습니다.");
        }
    }
}

 

 

SnackTest.java 코드

 

package developingman.sample_Project.snack;

import developingman.sample_Project.DependencyConfig;

public class SnackTest {
    public static void main(String[] args) {
        DependencyConfig dependencyConfig = new DependencyConfig();
        SnackService snackService = dependencyConfig.snackService();

        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("정상적으로 삭제 되었습니다.");
        }
    }
}

 

 

위와 같이 코드를 수정하였을 때 테스트가 정상 동작인 것을 확인하여 봅니다.

 

프레임워크의 도움이 아닌, 직접 파일 설정을 통해 의존성 주입을 할 수 있는 방식을 확인하여 보았습니다.

'Spring' 카테고리의 다른 글

[Spring] 빈(Bean)  (0) 2023.04.04
[Spring] 스프링 컨테이너(Spring Container)  (0) 2023.04.03
[Spring] 간단한 서비스 생성 및 테스트  (0) 2023.04.01
[Spring] Spring 환경 구성  (0) 2023.03.31
[Spring] Spring Framework란?(4)  (0) 2023.03.30