야미의 개발

[Spring] 의존성 주입(DI, Dependency Injection)과 스프링 컨테이너 본문

카테고리 없음

[Spring] 의존성 주입(DI, Dependency Injection)과 스프링 컨테이너

채야미 2024. 2. 8. 12:30

의존성이란?

 

객체가 다른 객체를 참조하고 있다면 현재 객체는 다른 객체에 의존성을 가집니다. 

한편 A객체가 B의 객체에 의존하고 그것에 맞게 코드를 짠 경우에는 B객체가 변경될때 A도 변경되어야할 가능성이 높습니다. 

소프트웨어 개체는 확장에는 열려있어야하고 변경에는 닫혀있어야 한다는 OCP (개방 폐쇄 원칙)을 생각해볼때 A가 B에 의존하는 것을 최대한 낮추어야 B가 변경될때 A의 변경이 최소화 될 수 있습니다.

 

가령 운전자와 자동차가 있다고 할때

// K3Car.java
public class K3Car {
    public void start() {
        System.out.println("K3Car is starting.");
    }

    public void drive() {
        System.out.println("K3Car is driving.");
    }

    public void stop() {
        System.out.println("K3Car has stopped.");
    }
}

// Driver.java
public class Driver {
    public static void main(String[] args) {
        // K3Car 객체 생성
        K3Car k3Car = new K3Car();

        // 운전 시작
        k3Car.start();

        // 운전 중
        k3Car.drive();

        // 운전 종료
        k3Car.stop();
    }
}

 

위의 드라이버 객체는 K3 객체를 의존하고 있습니다

 

의존성의 문제점

 

한편 위와 같이 드라이버 클래스를 K3의 구현에 맞추어

1. K3객체를 생성하고

2. K3의 메소드를 직접적으로 사용

하는 경우에는 

 

K3가 아닌 그랜저를 운전하고 싶을 때 

BMW의 객체를 생성하고 메소드를 사용하는 것까지 모두 변경해야하는 불상사가 일어날 수 있습니다.

 

-> 변경에 취약한 코드, 새로운 객체(자동차)를 추가하기 복잡한 코드

 

 

따라서 의존성을 낮추어 변경에 용이하고 구현체 교체(다른 자동차로 바꾸는일)와 추가를 편리하게 할 수 있는 방법이 필요합니다.

 

 

만약 드라이버 객체가 K3가 아닌 '자동차'에 초점을 맞추어 기능이 만들어지고

다른 제 3의 클래스가 드라이버 객체가 어떤 자동차, 특정한 구현체(K3, 그랜저)를 쓸지 정해준다면

코드 상에서 자동차가 추가되거나, 자동차를 바꿀때 변경이 줄어들고 쉬워집니다

 

// K3Car.java (Car 인터페이스를 구현한 K3차 구현체)
public class K3Car implements Car {
    @Override
    public void start() {
        System.out.println("K3Car is starting.");
    }

    @Override
    public void drive() {
        System.out.println("K3Car is driving.");
    }

    @Override
    public void stop() {
        System.out.println("K3Car has stopped.");
    }
}

// Driver.java (드라이버 클래스)
public class Driver {
    private Car car; // 인터페이스를 통한 의존성

    // 생성자를 통한 의존성 주입
    public Driver(Car car) {
        this.car = car;
    }

    public void driveCar() {
        // 자동차 운전
        car.start();
        car.drive();
        car.stop();
    }

}

 

위의 코드에서처럼 Driver 객체가 Car 인터페이스를 의존하게하면

Driver객체는 Car인터페이스의 어떤 구현체라도 제대로 동작할 수 있습니다. 

 

따라서 생성자에 사용할 구현체를 '주입'받게 하여 

다른 제 3의 클래스에서 Driver를 생성하면서 특정한 자동차 구현체를 주입하여 실제로 Driver가 Car를 운전할때 

주입된 구현체가 작동하도록 하는 것이 의존성 주입의 핵심입니다. 

 

 

스프링의 의존성 주입

스프링에서도 이러한 의존성 주입을 지원해줍니다.

어노테이션이나 XML을 통해 지정할 수 있으며

어노테이션 기반인 경우에는

어떤 구현체를 사용할 것인지 정하는 Config 파일에 @Configuration

사용할 객체에 @Bean 이라고 지정하여 특정 객체를 스프링 컨테이너에 등록할 수 있습니다. 

 

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

 

위와같은 코드가 스프링으로 의존성 주입을 구현한 것 입니다. 

 

 

 

https://gmlwjd9405.github.io/2018/11/09/dependency-injection.html

 

[Design Pattern] DI란 (Dependency Injection) - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

Comments