[Day 24 | Spring] DI(Dependency Injection, 의존성 주입)

y♡ding·2024년 11월 14일
0

데브코스 TIL

목록 보기
151/163

Spring IoC 컨테이너 및 Beans 소개 :: Spring Framework

Spring DI(Dependency Injection, 의존성 주입)는 스프링 프레임워크의 핵심 기능 중 하나로, 객체 간의 의존성을 프레임워크가 자동으로 관리해 주는 개념입니다. DI는 객체 생성과 관리의 책임을 프레임워크가 담당하게 함으로써 코드의 유연성과 유지보수성을 높여 줍니다. 이를 통해 의존성이 명확해지고 테스트가 용이해지는 장점이 있습니다.

1. DI의 기본 개념

  • 의존성: 한 객체가 다른 객체를 필요로 할 때, 그 객체와의 관계를 의존성이라고 합니다.
  • 의존성 주입: 필요로 하는 객체(의존성)를 외부에서 주입해 주는 것을 의미하며, 이를 통해 객체가 자신이 사용할 다른 객체에 대한 책임을 가지지 않도록 합니다.
  • IoC 컨테이너: 스프링의 IoC(Inversion of Control, 제어의 역전) 컨테이너가 객체의 생명 주기를 관리하며, 의존성을 자동으로 주입해 줍니다.

2. XML 기반 의존성 주입

스프링의 초기 설정 방식 중 하나로 XML 설정 파일을 사용하는 방법은 스프링 IoC 컨테이너에 의존성을 주입하고 빈 객체를 구성하는 전통적인 방식입니다. XML 파일을 통해 각 객체 간의 관계를 명시적으로 설정할 수 있어, 스프링의 의존성 주입과 빈 관리의 기본 개념을 이해하는 데 유리합니다.

1) XML 설정 파일을 사용한 빈(Bean) 정의와 의존성 주입

기본 XML 설정 구조

XML 설정 파일에서는 <bean> 태그를 사용하여 스프링 IoC 컨테이너가 관리할 빈을 정의합니다. 각 <bean> 태그는 특정 클래스를 정의하고, 해당 클래스의 의존성을 설정할 수 있습니다.

<beans xmlns="<http://www.springframework.org/schema/beans>"
       xmlns:xsi="<http://www.w3.org/2001/XMLSchema-instance>"
       xsi:schemaLocation="<http://www.springframework.org/schema/beans>
                           <http://www.springframework.org/schema/beans/spring-beans.xsd>">

    <!-- 빈 객체 정의 -->
    <bean id="sampleService" class="com.example.SampleService"/>
</beans>

위 설정에서 <bean> 요소는 SampleService라는 클래스를 빈으로 정의합니다. id 속성은 빈의 고유 식별자로, 이를 통해 다른 빈에서 참조할 수 있습니다.

2) XML 파일을 통한 의존성 주입 : 생성자 주입 (Constructor Injection)

생성자 주입은 constructor-arg 요소를 사용하여 의존성을 주입하는 방식입니다.

<beans>
    <!-- 의존성 클래스 정의 -->
    <bean id="dependencyClass" class="com.example.DependencyClass"/>

    <!-- 생성자 주입을 통해 의존성 주입 -->
    <bean id="sampleService" class="com.example.SampleService">
        <constructor-arg ref="dependencyClass"/>
    </bean>
</beans>
  • ref 속성은 다른 빈을 참조할 때 사용됩니다.
  • 위 예제에서 SampleServiceDependencyClass를 생성자를 통해 주입받습니다.

3. XML 설정 파일 사용 예제

아래 예제는 ApplicationContext를 통해 XML 파일로 설정된 빈을 로드하고 의존성을 주입받아 사용하는 방법을 보여줍니다.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        SampleService sampleService = (SampleService) context.getBean("sampleService");
        sampleService.performService();
    }
}

위 코드에서 beans.xml 파일을 통해 스프링 IoC 컨테이너가 설정됩니다. sampleService 빈을 가져와 메서드를 호출하면, 필요한 의존성이 XML 설정에 따라 주입됩니다.

DI 학습 시 주의할 점

  • 주입 방식의 선택: 생성자 주입을 기본으로 하고, 필요에 따라 필드나 Setter 주입을 사용합니다.
  • 빈 스코프: 의존성이 주입될 때 스코프(@Scope) 설정에 따라 싱글톤 또는 프로토타입으로 사용할 수 있습니다.
  • 테스트 환경에서의 주입: 생성자 주입을 통해 테스트 시에도 쉽게 Mocking을 적용할 수 있습니다.

DI의 종류 (애너테이션 기반)

스프링 DI는 여러 방식으로 이루어질 수 있습니다. 대표적으로 필드 주입, 생성자 주입, 그리고 Setter 주입이 있습니다.

1) 필드 주입 (Field Injection)

  • @Autowired를 사용하여 필드에 직접 의존성을 주입하는 방식입니다.
  • 코드가 간결하지만, 테스트 시에 Mocking이 어려워 권장되지 않는 방식이기도 합니다.
@Component
public class SampleService {
    @Autowired
    private DependencyClass dependency;
}

2) 생성자 주입 (Constructor Injection)

  • 생성자를 통해 의존성을 주입받는 방식으로, 스프링에서는 권장하는 주입 방식입니다.
  • 불변성을 보장하고, 주입받지 못하는 의존성이 있다면 컴파일 시점에 오류를 발생시킵니다.
@Component
public class SampleService {
    private final DependencyClass dependency;

    @Autowired
    public SampleService(DependencyClass dependency) {
        this.dependency = dependency;
    }
}

3) Setter 주입 (Setter Injection)

  • Setter 메서드를 사용하여 의존성을 주입받는 방식입니다.
  • 선택적으로 주입이 필요한 경우 유용하지만, 불변성이 보장되지 않기 때문에 주로 선택적 의존성에 사용됩니다.
@Component
public class SampleService {
    private DependencyClass dependency;

    @Autowired
    public void setDependency(DependencyClass dependency) {
        this.dependency = dependency;
    }
}

3. DI와 IoC 컨테이너의 역할

스프링의 IoC 컨테이너는 애플리케이션이 시작될 때 객체를 생성하고, 객체 간의 의존성을 자동으로 설정하여 주입합니다. 이 과정에서 다음과 같은 어노테이션이 자주 사용됩니다.

  • @Component: 빈(bean)으로 등록할 클래스를 정의할 때 사용합니다.
  • @Autowired: 스프링이 자동으로 의존성을 주입하도록 설정하는 어노테이션입니다.
  • @Qualifier: 동일한 타입의 빈이 여러 개 있을 때, 특정 빈을 주입할 때 사용합니다.

4. Spring DI 예제

아래는 간단한 DI 예제입니다. SampleServiceDependencyClass를 의존성으로 사용하며, IoC 컨테이너가 DependencyClass의 인스턴스를 주입해 줍니다.

@Component
public class DependencyClass {
    public void serve() {
        System.out.println("Service is being provided by DependencyClass");
    }
}

@Component
public class SampleService {
    private final DependencyClass dependency;

    @Autowired
    public SampleService(DependencyClass dependency) {
        this.dependency = dependency;
    }

    public void performService() {
        dependency.serve();
    }
}

관련 자료

0개의 댓글

관련 채용 정보