스프링 프레임워크에서 객체 의존성을 관리하기 위해 주로 사용되는 세 가지 어노테이션인 @Autowired, @Resource, 그리고 @Inject에 대해 설명하고, 각각의 특징과 차이점을 비교해 드리겠습니다. 이 어노테이션들은 모두 의존성 주입(Dependency Injection, DI)을 수행하는 데 사용되며, 스프링 애플리케이션에서 중요한 역할을 합니다.
의존성 주입이란
의존성 주입(Dependency Injection, DI)은 소프트웨어 엔지니어링에서 사용되는 디자인 패턴 중 하나로, 객체가 자신의 의존성(즉, 다른 객체들)을 직접 생성하거나 검색하지 않고, 외부에서 받도록 하는 기술입니다. 이 패턴을 사용하면 컴포넌트 간의 결합도가 낮아지고, 유연성이 향상되며, 코드의 재사용성과 테스트 용이성이 증가합니다.
의존성 주입 어노테이션
1. @Autowired (Spring Framework)
• 라이브러리: Spring Framework
• 기능: 타입에 기반하여 자동으로 의존성을 주입합니다. 만약 타입이 일치하는 빈이 여러 개 있는 경우, 필드 이름이나 파라미터 이름으로 빈을 구별하여 주입합니다.
• 주입 방법: 필드, 세터, 생성자 주입이 가능하며, 생성자 주입이 권장됩니다.
• 특징: @Autowired는 스프링의 기본 설정에서 자동으로 사용될 수 있으며, required 속성을 통해 의존성이 필수적인지 선택적인지 지정할 수 있습니다.
2. @Resource (Java Standard)
• 라이브러리: JSR-250, Java Standard
• 기능: 주로 이름에 기반하여 의존성을 주입합니다. 이름을 명시하지 않으면 필드의 이름 또는 세터 메서드의 이름을 사용합니다. 이름으로 적합한 빈을 찾지 못하면 타입에 의해 주입을 시도합니다.
• 주입 방법: 필드 및 세터 메서드에 사용될 수 있습니다.
• 특징: @Resource는 Java EE에서 제공되며, 스프링과 같은 DI 컨테이너에서도 사용할 수 있습니다. 스프링에서는 @Autowired보다는 약간 더 명시적인 의존성 주입 방식을 제공합니다.
3. @Inject (Java Dependency Injection)
• 라이브러리: JSR-330, Java Dependency Injection standard
• 기능: 타입에 기반하여 의존성을 주입합니다. @Autowired와 유사하게 작동하지만, required 속성이 없습니다.
• 주입 방법: 필드, 세터, 생성자 주입이 가능하며, 역시 생성자 주입이 권장됩니다.
• 특징: @Inject는 Java의 표준 의존성 주입 규약을 따르며, 스프링 뿐만 아니라 다른 DI 프레임워크에서도 사용될 수 있습니다. 스프링에서는 @Autowired와 거의 동일하게 작동하지만, 스프링 특유의 기능인 required 속성을 지원하지 않습니다.
비교
• 유연성 및 호환성: @Inject와 @Resource는 Java 표준을 따르므로, 다른 Java 기반 프레임워크로의 이동성이 더 높습니다. 반면, @Autowired는 스프링에 종속적입니다.
• 기능성: @Autowired는 required 속성을 통해 의존성이 필수인지 여부를 설정할 수 있어 더 많은 유연성을 제공합니다. @Inject는 이러한 속성이 없습니다.
• 사용의 용이성: @Autowired는 스프링 프레임워크에서 가장 일반적으로 사용되며, 스프링 특화 기능
위의 키워드 로 의존성 주입을 구현하는 방법
의존성 주입의 구현 방법
1. 생성자 주입: 객체를 생성할 때 생성자를 통해 의존성을 전달합니다. 이 방법이 가장 권장되는 방식으로, 객체의 불변성을 보장할 수 있습니다.
2. 세터 주입: 객체 생성 후 세터 메서드를 통해 의존성을 주입합니다. 생성자 주입에 비해 유연성은 높지만, 객체의 완전성을 보장받기 어려울 수 있습니다.
3. 필드 주입: 리플렉션을 사용하여 직접 필드에 의존성을 주입합니다. 코드는 간결해지지만, 다른 주입 방식에 비해 많은 단점을 가지고 있으며 권장되지 않습니다.
1. 생성자 주입(Constructor Injection)
생성자 주입은 가장 권장되는 방식입니다. 객체가 생성될 때 모든 의존성이 완전히 주입되기 때문에, 객체가 일관된 상태를 유지할 수 있습니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// UserService의 메서드
}
2. 세터 주입(Setter Injection)
세터 주입은 선택적 의존성이 필요할 때 유용할 수 있습니다. 이 방법을 사용하면 객체 생성 후 필요에 따라 의존성을 설정할 수 있습니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// UserService의 메서드
}
3. 필드 주입(Field Injection)
필드 주입은 코드는 간결하지만, 많은 단점을 가지고 있습니다. 특히, 테스트가 어렵고 순환 참조 문제가 발생할 수 있습니다. 따라서 권장되지 않는 방법입니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// UserService의 메서드
}
생성자 주입을 간단하게 해주는 어노테이션
@RequiredArgsConstructor는 Lombok 라이브러리의 주요 어노테이션 중 하나입니다. 이 어노테이션은 자바 클래스에 대해 필요한 생성자를 자동으로 생성해 주는 기능을 제공합니다. 사용하게 되면, 명시적으로 생성자를 작성하지 않아도 되므로 코드의 간결성을 유지할 수 있습니다.
@RequiredArgsConstructor의 작동 방식
@RequiredArgsConstructor 어노테이션이 적용된 클래스는 모든 final 필드와 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성합니다. 이 생성자는 해당 필드들을 초기화하는 역할을 하므로, 객체가 올바르게 구성되도록 보장합니다.
주요 특징
• 자동 생성자 생성: 클래스의 final 필드 또는 @NonNull이 붙은 필드에 대한 생성자를 자동으로 생성합니다.
• 코드의 간결성 증가: 생성자를 직접 작성하지 않아도 되므로, 코드를 더 간결하게 유지할 수 있습니다.
• 객체 불변성 지원: final 필드에 대한 생성자를 자동으로 생성하기 때문에 불변 객체를 만드는 데 유용합니다.
• Null 안정성 강화: @NonNull 어노테이션이 붙은 필드는 생성자에서 null 검사 로직을 자동으로 추가하여, 객체 생성 시 null이 되지 않도록 강제합니다.
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class User {
private final String name;
private final int age;
@NonNull
private String email;
// Lombok이 자동으로 다음 생성자를 생성해줍니다.
// public User(String name, int age, String email) {
// this.name = name;
// this.age = age;
// this.email = Objects.requireNonNull(email, "email is required");
// }
}
'Spring > spring framework 기본 및 이론' 카테고리의 다른 글
스프링과 스프링부트 차이점 (0) | 2024.05.27 |
---|---|
[SPRING] SPEL 스프링 표현식 (0) | 2021.02.08 |
[Spring] 스프링 어플리케이션 kill 시키기 (0) | 2020.09.27 |
[SPRING] mockMvc 유닛 테스트 (0) | 2020.06.16 |
[Spring] 스프링 mybatis transactions (0) | 2020.06.02 |