ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Framework 시리즈 2화 – @Component와 @Autowired로 의존성 주입 구현하기
    기술과 산업/언어 및 프레임워크 2025. 5. 20. 12:49
    728x90

    Spring의 의존성 주입(DI)을 구성하는 기본 애노테이션인 @Component와 @Autowired의 사용법과 주의사항을 실제 코드 예제와 함께 알아봅니다.

    의존성 주입(DI)은 왜 중요한가?

    Spring에서 **DI(Dependency Injection)**는 객체 간 의존 관계를 외부에서 주입받는 방식으로 구성해 유연성테스트 용이성을 확보합니다.
    직접 new로 객체를 생성하는 방식은 강한 결합을 유발하며, 테스트 시 Mock 객체를 주입하기도 어렵습니다.

    Spring은 이를 해결하기 위해 주요 애노테이션들을 제공합니다:

    • @Component: 스프링이 관리할 객체(빈)를 선언
    • @Autowired: 스프링 컨테이너에 등록된 빈을 자동으로 주입

    실습 예제 – 자동차와 엔진

    1. 의존 관계 정의

    // Engine.java
    package com.example.springcore;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Engine {
        public void start() {
            System.out.println("Engine started");
        }
    }
    
    // Car.java
    package com.example.springcore;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class Car {
    
        private final Engine engine;
    
        @Autowired // 생성자 주입
        public Car(Engine engine) {
            this.engine = engine;
        }
    
        public void drive() {
            engine.start();
            System.out.println("Car is moving");
        }
    }
    

    2. 실행 클래스

    // SpringCoreApplication.java
    package com.example.springcore;
    
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.ComponentScan;
    
    @SpringBootApplication
    public class SpringCoreApplication implements CommandLineRunner {
    
        private final Car car;
    
        public SpringCoreApplication(Car car) {
            this.car = car;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(SpringCoreApplication.class, args);
        }
    
        @Override
        public void run(String... args) {
            car.drive();
        }
    }
    

    이렇게 하면 스프링이 Engine을 자동으로 생성하고, Car 객체 생성 시 의존성을 주입해줍니다. 개발자는 직접 new 키워드를 사용하지 않아도 됩니다.


    @Component의 핵심 정리

    항목 설명

    역할 해당 클래스를 빈으로 등록함
    기본 이름 클래스명을 소문자로 시작 (engine, car)
    스캔 범위 @ComponentScan이 선언된 위치부터 하위 패키지만 스캔

    ※ 클래스가 하위 패키지에 없다면, 명시적으로 @ComponentScan("패키지명") 설정이 필요합니다.


    @Autowired의 3가지 방식

    Spring은 다음 3가지 방식으로 DI를 지원합니다:

    1. 생성자 주입 (추천)
      • 불변성 보장
      • 테스트 용이
      • 필드가 final이어야 함
    2. 필드 주입
    @Autowired
    private Engine engine;
    
    • 가장 간단하지만, 테스트에서 Mock 주입이 어려워 비권장
    1. 세터 주입
    private Engine engine;
    
    @Autowired
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
    
    • 선택적인 의존성에 사용 가능
    • 주로 Configuration 클래스에서 활용

    @Autowired 사용 시 주의사항

    1. 빈이 없으면 오류 발생
      → 기본적으로 필수 빈으로 간주되어, 주입 대상이 없으면 NoSuchBeanDefinitionException이 발생합니다.
    2. ✅ 해결 방법: @Autowired(required = false) 또는 Optional<Engine>
    3. 순환 참조 주의
      → 두 객체가 서로를 주입할 경우 UnsatisfiedDependencyException 발생
    4. 스프링이 관리하지 않는 객체에는 작동하지 않음
      → 반드시 @Component, @Configuration, 혹은 Bean으로 등록된 객체에서만 동작

    빈 수동 등록 – @Bean

    클래스를 수정할 수 없거나 외부 라이브러리인 경우에는 @Bean을 활용해 수동 등록이 가능합니다.

    @Configuration
    public class AppConfig {
    
        @Bean
        public Engine engine() {
            return new Engine();
        }
    }
    

    마무리 – @Component와 @Autowired는 Spring Core의 출발점

    Spring을 처음 학습하거나, 기존 Spring Boot 프로젝트에서 내부 구조를 이해하고 싶은 개발자라면 @Component와 @Autowired의 정확한 작동 원리를 아는 것이 중요합니다.

    이 두 애노테이션은 단순한 편의 기능이 아니라 스프링 컨테이너의 DI 구조를 이루는 핵심 구성요소입니다. 앞으로 나올 @Value, @Profile, @Configuration 등도 이 기반 위에 쌓인 기능들이죠.

     

    다음 3화에서는 @Configuration과 @Bean을 활용해 Java 기반으로 설정 클래스를 구성하고 빈을 등록하는 방법을 실습해보겠습니다.

    728x90
Designed by Tistory.