울음참고 개발공부
article thumbnail
728x90

 

 

 

의존성 주입하면 생각나는 것이 @Autowired 인데, 실제로 이것들의 정확한 개념은 설명할 수 없었다. 

@Autowired  를 사용하면 DI 를 편리하게 할 수 있다. 정도? 

 

 

그럼 얘들은 언제 어디에 어떻게 사용하는거지??

 

이번 정리를 통해 완벽하게 개념을 알고 있자 !! 

 


 

의존성 주입(Dependency Injection)

"소프트웨어 개발에서 다른 객체나 모듈로부터 필요한 의존성(객체, 서비스, 데이터 등)을 주입하는 디자인 패턴"
코드 간의 결합도를 낮추고 유지 보수성을 향상시키며 코드를 더 테스트하기 쉽게 하기 위함

 

 

먼저 DI 개념을 익히기 위해 스프링 프레임워크를 사용하지않고, 순수한 Java 코드로 의존성 주입을 해보자

 

아래 예시는 생성자 주입을 통한 의존성 주입이다.

 

 

 

  • Car 클래스 :  자동차를 나타내는 클래스로, Engin  객체에 의존한다
  • Engin 클래스 : 엔진을 나타내는 클래스로, Car 클래스에 주입할 것이다. 

 

 

public class Engine {
	public void start() {
    	System.out.println("Engine started");
    }
}

public class Car {
	private Engine engine;
    
    public Car(Engine engine) {
    	this.engine = engine;
    }
    
    public void start() {
    	System.out.println("Car is starting");
        engine.start();
    }
}

 

 

위의 예시에서 Car 클래스는 Engine 객체에 의존하며, Car 생성자를 통해 Engine 객체를 주입받는다.

 

 

의존성을 주입하려면 다음과 같이 객체를 생성하고 주입해야한다.

 

public class Main {
	public static void main(String[] args) {
    	Engine engine = new Engine(); // 엔진 객체 생성
        Car car = new Car(engine); // 자동차 객체 생성 및 엔진 주입
        
        car.start(); // 자동차 시작 
    }
}

 

이렇게 하면 Car 객체가 Engine 객체를 사용할 수 있게되는 것이다.

 

의존성 주입은 객체 간의 결합도를 낮추고 재사용성을 높이는데 도움을 준다. 

 

 

 


 

 

 

그럼 이제 똑같은 예시로 스프링 프레임워크를 사용하여 의존성 주입을 해보자

 

 

Engine 클래스 

import org.springframework.stereotype.Component;

@Component
public class Engine {
    public void start() {
        System.out.println("Engine started");
    }
}

 

 

 

Car 클래스 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Car {
    private Engine engine;

    @Autowired // 생성자를 통한 의존성 주입 
    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        System.out.println("Car is starting.");
        engine.start();
    }
}

 

 

@Autowired 역할

@Autowired를 사용하면 스프링은 Car 클래스가 필요로 하는 Engine 빈을 자동으로 찾아서 Car객체에 주입합니다

 

 

@Componet 어노테이션을 Car클래스와 Engine 클래스에 사용하였으므로 두 클래스는 스프링 빈에 등록된다. 

이렇게 스프링 빈으로 등록해두면 @Autowired 가 붙은 필드, 생성자, 메서드 등의 매개변수에 해당하는 빈을 스프링이 찾아서 자동으로 주입해 주는 것이다. 

 

(참고 : 스프링 빈으로 등록되는 시점은 애플리케이션이 시작될 때 스프링 컨테이너가 생성되고 빈을 읽을 때이다) 

 

 

 

 

실행 코드 

 

@Configuration
@ComponentScan
public class AppConfig {

}

 

 

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Car car = context.getBean(Car.class);
        car.start();
    }
}

 

 

 


 

[ 요약 ]

 

정리하자면 ,  순수 Java 로 의존성을 주입할 때는 Engine 객체를 직접 넣어주었는데 

@Autowired 를 사용하면 필요시 빈에 등록된 객체들 중에서 찾아서 알아서 주입해준다는 것이다. 

 

원래 개발자가 하던 일을 스프링이 빈에서 찾아서 알아서 해주니 이것을 '제어의 역전(IoC; Inversion of Controle) ' 이라고 하며 스프링 프레임워크의 핵심이기도 하다. 

 

 

의존성 주입을 사용해야 하는 이유:
객체 간의 결합도를 줄이고 재사용성을 높이기 위해.테스트하기 쉬운 코드를 작성하기 위해.

어디에 사용해야 하는가:
스프링과 같은 의존성 주입 프레임워크에서.테스트 가능한 코드를 작성할 때.

어떻게 사용해야 하는가:
생성자 주입, 메서드 주입 또는 속성 주입을 통해 의존성을 주입.객체가 필요한 의존성을 직접 생성하지 않고 외부에서 주입받음

 

 

 


 

+ 추가 )

 

의존성 주입과 관련하여 Car 클래스와 Engine 클래스 예시를 사용하였는데 이는 DIP 원칙에 위배된 설계이긴하다.

그 이유는 Car 클래스가 Engine 클래스에 직접 의존하고 있기 때문이다.

 

DIP 를 준수하려면 Car 클래스가 Engine 클래스 대신 인터페이스 또는 추상 클래스를 사용하고,

Engine 클래스가 해당 인터페이스를 구현하도록 설계해야한다.  

 

예를 들어 아래와 같이 설계할 수 있다.

 

 

Engine 인터페이스 

public interface Engine{
	void start();
}

 

 

Engine 상속받은 구체 클래스 

@Component
public class ElectricEngine implements Engine {
	@Overrude
    public void start() {
    	System.out.println("Electric engiene started");
    }
}

 

 

Car 클래스 

@Component
public class Car {
	private Engine engine;
    
    @Autowired
    public Car(Engine engine) {
    	this.engine = engine; 
    }
    
    public void start() {
    	Syetem.out.println("Car is starting");
        engine.start();
    }
}

 

 

이렇게 작성하면 Car  클래스가 인터페이스에 의존하고 있기 때문에 DIO 를 준수할 수 있게 된다. 

또한 어떤 구현체를 주입받더라도 동작할 수 있어  Car 클래스와 Engine  클래스 사이의 의존성이 느슨하게 되어 코드의 재사용성과 확장성이 향상된다. 

 

 

 

728x90
profile

울음참고 개발공부

@메각이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!