정보

[Spring Boot 3 완벽 가이드] @Autowired 어노테이션 사용법과 필드/생성자/세터 주입 예제 총정리

mindlab091904 2025. 5. 9. 16:36
반응형

 

Spring Boot를 처음 배우거나 실무에서 사용 중인 분들이 가장 자주 접하게 되는 어노테이션 중 하나가 바로 @Autowired입니다. 이 어노테이션은 스프링 프레임워크가 제공하는 의존성 주입(Dependency Injection, DI)을 간단하게 구현할 수 있도록 도와주는 핵심 도구입니다. 이번 포스팅에서는 Spring Boot 3 기준으로 @Autowired 어노테이션의 개념, 사용법, 주입 방식별 예제, 그리고 선택적 의존성 주입을 위한 required=false 옵션까지 상세하게 다뤄보겠습니다.


🔍 @Autowired란 무엇인가요?

@Autowired는 스프링 프레임워크에서 제공하는 어노테이션으로, 스프링 컨테이너가 관리하는 Bean(빈) 객체를 자동으로 주입받기 위해 사용합니다. 즉, 개발자가 직접 객체를 생성하거나 관리할 필요 없이, 스프링이 대신 해당 의존성을 찾아서 주입해주기 때문에 코드의 간결성과 유지보수성이 크게 향상됩니다.

간단히 말해, @Autowired는 스프링이 알아서 객체를 "넣어주는" 역할을 하며, 다음과 같은 상황에서 주로 사용됩니다.

  • 서비스 클래스에서 DAO(Repository)를 주입받을 때
  • 컨트롤러에서 서비스 클래스를 사용할 때
  • 구성 클래스나 유틸 클래스 등에서 다른 Bean을 사용할 때

✅ @Autowired 사용 위치별 예제

@Autowired는 다음 세 가지 위치에서 사용 가능합니다.

  1. 필드(Field) 주입
  2. 생성자(Constructor) 주입
  3. 세터(Setter) 주입

각 방식마다 특징과 장단점이 있으므로, 하나씩 구체적인 예제를 통해 살펴보겠습니다.


1️⃣ 필드(Field) 주입

필드 주입은 클래스 내의 특정 멤버 변수(필드)에 직접 @Autowired 어노테이션을 붙이는 방식입니다.

@RestController
public class AutowiredController {

    @Autowired
    private AutowiredService service;

    @GetMapping("/hello")
    public String hello() {
        return service.sayHello();
    }
}

✅ 특징 및 장점

  • 코드가 가장 간결하고 직관적입니다.
  • 가장 많이 사용하는 방식이기도 합니다.

⚠️ 주의할 점

  • 테스트 코드 작성 시 Mock 주입이 어려울 수 있습니다.
  • 순환 참조 발생 시 해결이 어려운 구조가 될 수 있습니다.
  • 생성자 또는 세터 방식보다 명시성이 떨어집니다.

2️⃣ 생성자(Constructor) 주입

Spring Boot 3에서는 생성자 주입이 가장 권장되는 방식입니다. 이 방식은 의존성을 불변(final) 필드로 선언할 수 있어 안전성이 높습니다.

@RestController
public class AutowiredController {

    private final AutowiredService service;

    @Autowired
    public AutowiredController(AutowiredService service) {
        this.service = service;
    }

    @GetMapping("/hello")
    public String hello() {
        return service.sayHello();
    }
}

✅ 특징 및 장점

  • 테스트 용이성이 뛰어납니다.
  • final 키워드를 활용해 불변 객체 주입이 가능합니다.
  • Spring Boot 4.3 이후부터는 생성자가 하나뿐이라면 @Autowired 생략도 가능합니다.
public AutowiredController(AutowiredService service) {
    this.service = service;
}

⚠️ 주의할 점

  • 주입받는 필드가 많아질 경우 생성자 코드가 길어질 수 있습니다.

3️⃣ 세터(Setter) 주입

세터 메서드를 통해 의존성을 주입받는 방식입니다. 주입 대상이 선택적(optional)일 때 사용하기 좋습니다.

@RestController
public class AutowiredController {

    private AutowiredService service;

    @Autowired
    public void setService(AutowiredService service) {
        this.service = service;
    }

    @GetMapping("/hello")
    public String hello() {
        return service.sayHello();
    }
}

✅ 특징 및 장점

  • 의존성 주입이 선택적일 때 유용합니다.
  • 나중에 값을 변경할 수 있습니다.

⚠️ 주의할 점

  • 객체가 불완전한 상태로 사용될 수 있습니다.
  • 테스트 시 오용될 가능성이 있으므로 주의가 필요합니다.

🧩 @Autowired(required = false) 사용법

기본적으로 @Autowired는 주입할 Bean이 반드시 존재해야 하며, 존재하지 않으면 NoSuchBeanDefinitionException 예외가 발생하여 애플리케이션이 실행되지 않습니다. 그러나 가끔 의존성 객체가 선택적으로 존재할 수도 있는 상황이 있습니다.

이럴 때 사용하는 옵션이 바로 required = false입니다.


❗왜 required=false가 필요한가요?

  • 특정 Bean이 환경에 따라 등록되지 않을 수도 있을 때
  • 테스트 코드나 임시 설정에서 의존성 주입이 항상 필요하지 않을 때
  • 서드파티 라이브러리 등에서 선택적인 의존성이 필요한 경우

🔧 필드 주입 + required=false 예제

@Autowired(required = false)
private AutowiredService service;

🔧 생성자 주입 + required=false 예제

private final AutowiredService service;

@Autowired
public AutowiredController(@Autowired(required = false) AutowiredService service) {
    this.service = service;
}

🔧 세터 주입 + required=false 예제

private AutowiredService service;

@Autowired
public void setService(@Autowired(required = false) AutowiredService service) {
    this.service = service;
}

⚠️ 주의할 점

  • required = false로 설정하면 주입 대상 Bean이 존재하지 않을 경우 null로 주입됩니다.
  • null 체크 로직을 반드시 포함해야 NullPointerException을 방지할 수 있습니다.
if (service != null) {
    service.doSomething();
}

🧠 정리하며: 어떤 방식으로 @Autowired를 사용하는 것이 좋을까?

주입 방식 장점 단점 권장 여부

필드 주입 간결함 테스트 어려움, 순환 참조 문제 ❌ (테스트 중심 개발 시 비권장)
생성자 주입 불변성, 테스트 용이 생성자 길어질 수 있음 ✅ (스프링 권장)
세터 주입 선택적 의존성 주입에 유리 객체가 불완전할 수 있음 ⭕ (특정 상황에서 유용)

스프링 공식 문서와 실무 경험에 따르면, 생성자 주입을 기본으로 하고, 선택적인 의존성에는 세터 주입, 가급적이면 필드 주입은 지양하는 것이 가장 안정적이고 유지보수하기 좋은 설계 방법입니다.


✨ 마무리하며

이번 포스팅에서는 Spring Boot 3 기준으로 @Autowired 어노테이션의 사용법과 필드, 생성자, 세터 주입 방식의 차이점, 그리고 required = false 옵션을 활용한 선택적 의존성 주입까지 깊이 있게 살펴보았습니다.

의존성 주입은 스프링의 가장 핵심적인 기능 중 하나로, 제대로 이해하고 사용하는 것이 클린하고 유연한 구조의 애플리케이션을 만드는 데 큰 도움이 됩니다.

다음 포스팅에서는 @Qualifier, @Primary 등을 활용한 Bean 충돌 해결법에 대해서도 자세히 다뤄보겠습니다. 기대해주세요!

 

반응형