개발자 공부/♡ Spring XML

Spring의 의존성 주입(DI) 4가지 방식 [ @Autowired, 생성자, 컬렉션, Setter ]

유정♡ 2025. 2. 3. 17:18

DI(Dependency Injection, 의존성 주입)란?
👉 객체를 직접 생성하는 대신, 외부에서 주입해주는 방식
👉 코드의 유지보수성 증가, 객체 간 결합도 감소


🔥 1️⃣ 자동(Annotation 기반) DI (@Autowired)

💡 Spring이 자동으로 객체를 주입해주는 방식

✅ @Autowired 어노테이션을 사용하면, Spring이 해당 타입의 Bean을 자동으로 찾아서 주입해줌
✅ XML 설정 없이 간단하게 사용할 수 있음

📌 코드 예제

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

@Component  // Engine 클래스를 Bean으로 등록
public class Engine {
    private String type = "V8 Engine";

    public String getType() {
        return type;
    }
}

@Component  // Car 클래스를 Bean으로 등록
public class Car {
    private Engine engine;

    @Autowired  // 자동으로 Engine 객체 주입
    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public void showEngineType() {
        System.out.println("Car engine: " + engine.getType());
    }
}

📌 실행 코드

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

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

        Car car = context.getBean(Car.class);
        car.showEngineType();  // 출력: Car engine: V8 Engine
    }
}

✅ @Autowired 방식의 장점

XML 설정 없이 편리하게 사용 가능
타입을 기준으로 주입되므로 코드가 간결해짐


🔥 2️⃣ 생성자(Constructor) DI

💡 객체 생성 시, 생성자를 통해 필요한 의존성을 주입하는 방식

필수적인 의존성 주입에 적합함 (불변성 유지 가능)
Spring 4.3 이상에서는 @Autowired 생략 가능

📌 코드 예제 (XML 방식)

<bean id="engine" class="com.example.Engine">
    <constructor-arg value="V8 Engine"/>
</bean>

<bean id="car" class="com.example.Car">
    <constructor-arg ref="engine"/>
</bean>

📌 Java 코드

public class Engine {
    private String type;

    public Engine(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }
}

public class Car {
    private Engine engine;

    public Car(Engine engine) {  // 생성자를 통해 Engine 객체를 받음
        this.engine = engine;
    }

    public void showEngineType() {
        System.out.println("Car engine: " + engine.getType());
    }
}

✅ 생성자 DI 방식의 장점

객체가 생성될 때 반드시 필요한 값이 설정됨 (필수 의존성)
객체가 불변(Immutable)하게 유지될 수 있음


🔥 3️⃣ 컬렉션(Collection) DI

💡 여러 개의 객체(List, Set, Map)를 한꺼번에 주입하는 방식

여러 개의 Bean을 한 번에 주입할 때 사용
List, Set, Map 같은 컬렉션 타입으로 묶어서 주입 가능

📌 코드 예제 (XML 방식)

<bean id="engine1" class="com.example.Engine">
    <constructor-arg value="V8 Engine"/>
</bean>

<bean id="engine2" class="com.example.Engine">
    <constructor-arg value="Electric Engine"/>
</bean>

<bean id="garage" class="com.example.Garage">
    <property name="engines">
        <list>
            <ref bean="engine1"/>
            <ref bean="engine2"/>
        </list>
    </property>
</bean>

📌 Java 코드

import java.util.List;

public class Garage {
    private List<Engine> engines;

    public void setEngines(List<Engine> engines) {  // 컬렉션 주입
        this.engines = engines;
    }

    public void showEngines() {
        for (Engine engine : engines) {
            System.out.println("Engine type: " + engine.getType());
        }
    }
}

📌 실행 코드

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

Garage garage = context.getBean("garage", Garage.class);
garage.showEngines();

// 출력:
// Engine type: V8 Engine
// Engine type: Electric Engine

✅ 컬렉션 DI 방식의 장점

여러 개의 객체를 한꺼번에 관리 가능
리스트, 맵 등 다양한 자료구조를 쉽게 주입 가능


🔥 4️⃣ Setter DI

💡 Setter 메서드를 이용해서 의존성을 주입하는 방식

선택적으로 의존성을 설정할 때 유용
객체를 먼저 만들고, 이후에 값을 설정할 수 있음

✅ 객체를 만든 후, set메서드를 이용해 값을 넣어주는 방식이야!
✅ 객체가 만들어진 후에도 값을 변경할 수 있어 유연함

2️⃣ Java 코드 작성

✅ Engine 클래스 (엔진)

package com.example;

public class Engine {
    private String type;  // 엔진 종류

    public void setType(String type) {  // Setter 메서드 (나중에 값을 설정)
        this.type = type;
    }

    public String getType() {  // 엔진 종류 가져오기
        return type;
    }
}

✅ Engine 객체를 만들 때 바로 값을 넣지 않고, 나중에 setType() 메서드로 설정 가능!


✅ Car 클래스 (자동차)

package com.example;

public class Car {
    private Engine engine;  // 자동차가 사용할 엔진

    public void setEngine(Engine engine) {  // Setter 메서드 (나중에 엔진을 설정)
        this.engine = engine;
    }

    public void showEngineType() {
        if (engine != null) {
            System.out.println("Car engine: " + engine.getType());
        } else {
            System.out.println("Engine not installed!");
        }
    }
}

✅ Car 객체를 만들 때 바로 엔진을 설정하지 않아도 됨!
✅ 나중에 setEngine() 메서드를 호출해서 엔진을 설정할 수 있음.


3️⃣ XML 설정 (beans.xml)

💡 Spring이 자동으로 객체를 만들고, Setter 메서드로 값을 넣어줌!

<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">

    <!-- Engine 객체 생성 -->
    <bean id="engine" class="com.example.Engine">
        <property name="type" value="V8 Engine"/>  <!-- setType("V8 Engine") 실행됨! -->
    </bean>

    <!-- Car 객체 생성 -->
    <bean id="car" class="com.example.Car">
        <property name="engine" ref="engine"/>  <!-- setEngine(engine) 실행됨! -->
    </bean>

</beans>

🔍 XML 코드 설명

1️⃣ Spring이 engine 객체를 먼저 생성
2️⃣ setType("V8 Engine") 메서드를 자동 실행해서 엔진 종류를 설정
3️⃣ 그 다음 car 객체를 생성
4️⃣ setEngine(engine)을 자동 실행해서 car에 engine을 넣어줌

Spring이 알아서 setType()과 setEngine()을 실행해줌!


4️⃣ 실행 코드 (Main.java)

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

public class Main {
    public static void main(String[] args) {
        // 🔥 Spring 컨테이너 실행 (XML 설정을 읽어옴)
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        // 🚗 "car"라는 id의 Bean(객체) 가져오기
        Car car = context.getBean("car", Car.class);

        // 🚗 자동차의 엔진 정보 출력
        car.showEngineType();  // 출력: Car engine: V8 Engine
    }
}

5️⃣ 실행 결과

Car engine: V8 Engine

🎯 자동차(Car)가 먼저 만들어지고, Spring이 setEngine()을 실행해서 엔진(Engine)을 넣어줬다!
🎯 즉, 객체를 먼저 만들고, 나중에 값을 넣는 방식이 Setter 주입!


📌 4가지 DI 방식 비교 정리

DI 방식주입 방식특징장점단점

자동(@Autowired) @Autowired 사용 Spring이 자동으로 주입 XML 없이 간결 같은 타입의 Bean이 여러 개면 오류 발생 가능
생성자(Constructor) DI 생성자를 통해 주입 불변성 유지 가능, 필수 의존성 주입 코드 안정성 높음 생성자에 의존성이 많아지면 복잡해질 수 있음
컬렉션(Collection) DI List, Set, Map을 주입 여러 객체를 한 번에 주입 가능 그룹으로 객체 관리 가능 복잡한 설정 필요
Setter DI Setter 메서드로 주입 선택적 의존성 설정 가능 유연한 설정 가능 필수 의존성을 강제할 수 없음

🔥 결론

  • @Autowired(자동 주입)Spring이 자동으로 관리, 가장 간편함
  • 생성자 주입필수 의존성 주입에 적합, 불변성을 보장
  • 컬렉션 주입리스트, 맵 등의 여러 객체를 한 번에 주입 가능
  • Setter 주입선택적 의존성 주입 가능, 유연한 설정 가능
728x90