Loading...
Spring Framework Reference Documentation 7.0.2의 Using @Autowired의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
@AutowiredJSR 330의
@Inject어노테이션은 이 섹션에 포함된 예제에서 Spring의@Autowired어노테이션 대신 사용할 수 있습니다. 자세한 내용은 here를 참조하세요.
다음 예제에서 보는 것처럼 @Autowired 어노테이션을 생성자에 적용할 수 있습니다:
1public class MovieRecommender { 2 3 private final CustomerPreferenceDao customerPreferenceDao; 4 5 @Autowired 6 public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { 7 this.customerPreferenceDao = customerPreferenceDao; 8 } 9 10 // ... 11}
1class MovieRecommender @Autowired constructor( 2 private val customerPreferenceDao: CustomerPreferenceDao 3)
대상 빈이 하나의 생성자만 정의하는 경우, 해당 생성자에
@Autowired어노테이션을 붙일 필요는 없습니다. 그러나 여러 개의 생성자가 있고 primary 또는 기본 생성자가 없는 경우에는, 어느 생성자를 사용할지 컨테이너에 지시하기 위해 적어도 하나의 생성자에는@Autowired를 어노테이션으로 붙여야 합니다. 자세한 내용은 constructor resolution에 대한 논의를 참조하세요.
다음 예제에서 보는 것처럼 traditional setter 메서드에 @Autowired 어노테이션을 적용할 수 있습니다:
1public class SimpleMovieLister { 2 3 private MovieFinder movieFinder; 4 5 @Autowired 6 public void setMovieFinder(MovieFinder movieFinder) { 7 this.movieFinder = movieFinder; 8 } 9 10 // ... 11}
1class SimpleMovieLister { 2 3 @set:Autowired 4 lateinit var movieFinder: MovieFinder 5 6 // ... 7}
다음 예제에서 보는 것처럼 임의의 이름과 여러 argument를 가진 메서드에 @Autowired를 적용할 수 있습니다:
1public class MovieRecommender { 2 3 private MovieCatalog movieCatalog; 4 5 private CustomerPreferenceDao customerPreferenceDao; 6 7 @Autowired 8 public void prepare(MovieCatalog movieCatalog, 9 CustomerPreferenceDao customerPreferenceDao) { 10 this.movieCatalog = movieCatalog; 11 this.customerPreferenceDao = customerPreferenceDao; 12 } 13 14 // ... 15}
1class MovieRecommender { 2 3 private lateinit var movieCatalog: MovieCatalog 4 5 private lateinit var customerPreferenceDao: CustomerPreferenceDao 6 7 @Autowired 8 fun prepare( 9 movieCatalog: MovieCatalog, 10 customerPreferenceDao: CustomerPreferenceDao 11 ) { 12 this.movieCatalog = movieCatalog 13 this.customerPreferenceDao = customerPreferenceDao 14 } 15 16 // ... 17}
다음 예제에서 보는 것처럼 필드에도 @Autowired를 적용할 수 있으며, 이를 생성자와 혼합해서 사용할 수도 있습니다:
1public class MovieRecommender { 2 3 private final CustomerPreferenceDao customerPreferenceDao; 4 5 @Autowired 6 private MovieCatalog movieCatalog; 7 8 @Autowired 9 public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) { 10 this.customerPreferenceDao = customerPreferenceDao; 11 } 12 13 // ... 14}
1class MovieRecommender @Autowired constructor( 2 private val customerPreferenceDao: CustomerPreferenceDao 3) { 4 5 @Autowired 6 private lateinit var movieCatalog: MovieCatalog 7 8 // ... 9}
대상 컴포넌트(예:
MovieCatalog또는CustomerPreferenceDao)가@Autowired가 붙은 인젝션 포인트에 사용한 타입으로 일관되게 선언되어 있는지 반드시 확인해야 합니다. 그렇지 않으면 런타임에 "no type match found" 에러로 인해 인젝션이 실패할 수 있습니다. XML로 정의된 빈이나 클래스패스 스캐닝을 통해 발견된 컴포넌트 클래스의 경우, 컨테이너는 일반적으로 사전에 구체적인 타입을 알고 있습니다. 그러나@Bean팩토리 메서드의 경우에는, 선언된 반환 타입이 충분히 표현력이 있도록 해야 합니다. 여러 인터페이스를 구현하는 컴포넌트나 구현 타입으로 참조될 수 있는 컴포넌트의 경우, 팩토리 메서드에서 가장 구체적인 반환 타입을 선언하세요(적어도 해당 빈을 참조하는 인젝션 포인트에서 요구하는 수준만큼은 구체적이어야 합니다).
@Autowired는 인젝션 시 self reference(즉, 현재 인젝션되고 있는 빈에 대한 역참조)도 고려합니다.
그러나 self 인젝션은 폴백 메커니즘이라는 점에 유의해야 합니다. 다른 컴포넌트에 대한 일반적인 의존성이 항상 우선합니다. 그런 의미에서 self reference는 일반적인 자동 주입 후보 선택에 참여하지 않으며, 특히 primary가 되는 일은 결코 없습니다. 반대로 self reference는 항상 가장 낮은 우선순위를 갖게 됩니다.
실무에서는 self reference를 마지막 수단으로만 사용해야 합니다. 예를 들어, 빈의 트랜잭션 프록시를 통해 동일한 인스턴스의 다른 메서드를 호출하는 경우가 이에 해당합니다. 이러한 상황에서는 영향을 받는 메서드를 별도의 delegate 빈으로 분리하는 방안을 고려해 보세요.
또 다른 대안으로, 고유한 이름으로 현재 빈에 대한 프록시를 얻을 수 있는 @Resource를 사용할 수도 있습니다.
동일한
@Configuration클래스 내의@Bean메서드에서 나온 결과를 주입하려는 시도도 실질적으로 self-reference 시나리오에 해당합니다. 이러한 reference는 configuration 클래스의 자동 주입된 필드가 아니라 실제로 필요한 메서드 시그니처에서 지연해서 resolve하거나, 해당@Bean메서드를static으로 선언하여 포함하고 있는 configuration 클래스 인스턴스 및 그 라이프사이클과 분리해야 합니다. 그렇지 않으면 이러한 빈은 폴백 단계에서만 고려되며, 대신 다른 configuration 클래스에 있는 매칭 빈이 primary 후보로 선택됩니다(가능한 경우).
또한, 다음 예제에서 보는 것처럼 특정 타입의 모든 빈을 ApplicationContext에서 제공하도록 Spring에 지시할 수 있습니다. 그러려면 해당 타입의 배열을 기대하는 필드나 메서드에 @Autowired 어노테이션을 추가하면 됩니다:
1public class MovieRecommender { 2 3 @Autowired 4 private MovieCatalog[] movieCatalogs; 5 6 // ... 7}
1class MovieRecommender { 2 3 @Autowired 4 private lateinit var movieCatalogs: Array<MovieCatalog> 5 6 // ... 7}
다음 예제에서 보는 것처럼 타입이 지정된 컬렉션에도 동일한 내용이 적용됩니다:
1public class MovieRecommender { 2 3 private Set<MovieCatalog> movieCatalogs; 4 5 @Autowired 6 public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) { 7 this.movieCatalogs = movieCatalogs; 8 } 9 10 // ... 11}
1class MovieRecommender { 2 3 @Autowired 4 lateinit var movieCatalogs: Set<MovieCatalog> 5 6 // ... 7}
배열이나 리스트의 항목을 특정 순서로 정렬하고 싶다면, 대상 빈이
org.springframework.core.Ordered인터페이스를 구현하거나@Order또는 표준@Priority어노테이션을 사용할 수 있습니다. 그렇지 않으면, 해당 항목의 순서는 컨테이너에 등록된 대상 빈 정의의 등록 순서를 따릅니다.@Order어노테이션은 대상 클래스 레벨과@Bean메서드에 선언할 수 있으며, 동일한 빈 클래스를 사용하는 여러 정의가 있는 경우에는 개별 빈 정의에 선언할 수도 있습니다.@Order값은 인젝션 포인트에서의 우선순위에 영향을 줄 수 있지만, 싱글톤 시작 순서에는 영향을 주지 않는다는 점에 유의해야 합니다. 싱글톤 시작 순서는 의존성 관계와@DependsOn선언에 의해 결정되는 별도의 관심사입니다. configuration 클래스에 선언된@Order어노테이션은 시작 시 전체 configuration 클래스 집합 내에서의 평가 순서에만 영향을 미칩니다. 이러한 configuration-level 순서 값은 포함된@Bean메서드에는 전혀 영향을 주지 않습니다. 빈 레벨 순서를 위해서는, 각@Bean메서드가 자신만의@Order어노테이션을 가져야 하며, 이는 특정 빈 타입에 대한 여러 매치 집합 내(해당 팩토리 메서드가 반환하는 대로)에서 적용됩니다. 표준jakarta.annotation.Priority어노테이션은 메서드에 선언할 수 없기 때문에@Bean레벨에서는 사용할 수 없습니다. 이 어노테이션의 의미는 각 타입마다 하나의 빈에 대해@Primary와 결합된@Order값으로 모델링할 수 있습니다.
예상 키 타입이 String인 한, 타입이 지정된 Map 인스턴스도 자동 주입할 수 있습니다.
맵의 값은 모두 예상 타입의 빈이며, 키는 해당 빈 이름입니다. 다음 예제에서 보는 것처럼 사용할 수 있습니다:
1public class MovieRecommender { 2 3 private Map<String, MovieCatalog> movieCatalogs; 4 5 @Autowired 6 public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) { 7 this.movieCatalogs = movieCatalogs; 8 } 9 10 // ... 11}
1class MovieRecommender { 2 3 @Autowired 4 lateinit var movieCatalogs: Map<String, MovieCatalog> 5 6 // ... 7}
기본적으로, 특정 인젝션 포인트에 대해 일치하는 후보 빈이 하나도 없는 경우 자동 주입은 실패합니다. 선언된 배열, 컬렉션, 맵의 경우에는 적어도 하나의 일치하는 요소가 있어야 합니다.
기본 동작은 어노테이션이 붙은 메서드와 필드를 필수 의존성을 나타내는 것으로 취급하는 것입니다. 다음 예제에서 보이는 것처럼 이 동작을 변경하여, @Autowired에서 required 속성을 false로 설정해 해당 인젝션 포인트를 non-required(즉, 필수가 아님)로 표시함으로써 프레임워크가 만족시킬 수 없는 인젝션 포인트를 건너뛸 수 있도록 할 수 있습니다:
1public class SimpleMovieLister { 2 3 private MovieFinder movieFinder; 4 5 @Autowired(required = false) 6 public void setMovieFinder(MovieFinder movieFinder) { 7 this.movieFinder = movieFinder; 8 } 9 10 // ... 11}
1class SimpleMovieLister { 2 3 @Autowired(required = false) 4 var movieFinder: MovieFinder? = null 5 6 // ... 7}
non-required 메서드는 해당 의존성(또는 여러 argument의 경우 그 중 하나의 의존성)이 사용할 수 없는 경우 아예 호출되지 않습니다. non-required 필드는 이러한 경우 전혀 값이 채워지지 않으며, 기본값이 그대로 유지됩니다. 다시 말해,
required속성을false로 설정하는 것은 해당 프로퍼티가 자동 주입 관점에서 optional 하다는 것을 나타내며, 자동 주입할 수 없는 경우 해당 프로퍼티는 무시됩니다. 이를 통해 프로퍼티에 기본값을 할당하고, 필요하다면 의존성 주입을 통해 선택적으로 오버라이드할 수 있습니다.
인젝션된 생성자와 팩토리 메서드 argument는 @Autowired의 required 속성이 Spring의 생성자 resolve 알고리즘 때문에 다소 다른 의미를 가지므로 특별한 경우입니다. 이 알고리즘은 잠재적으로 여러 생성자를 다룰 수 있습니다. 생성자와 팩토리 메서드 argument는 사실상 기본적으로 필수이지만, single-constructor 시나리오에서는 몇 가지 특별한 규칙이 적용됩니다. 예를 들어, multi-element 인젝션 포인트(배열, 컬렉션, 맵)가 일치하는 빈이 없는 경우 빈 인스턴스로 resolve될 수 있습니다. 이를 통해 모든 의존성을 고유한 multi-argument 생성자에 선언하는 일반적인 구현 패턴을 사용할 수 있습니다. 예를 들어, @Autowired 어노테이션이 없는 단일 public 생성자로 선언할 수 있습니다.
어떤 빈 클래스든
required속성이true로 설정된@Autowired를 선언할 수 있는 생성자는 하나만 있을 수 있으며, 이는 Spring 빈으로 사용할 때 자동 주입할 그 생성자를 나타냅니다. 결과적으로,required속성이 기본값인true로 유지되는 경우에는 오직 하나의 생성자만@Autowired로 어노테이션을 붙일 수 있습니다. 여러 생성자가 어노테이션을 선언하는 경우, 모두 자동 주입 후보로 간주되기 위해서는required=false를 선언해야 합니다(XML에서의autowire=constructor와 유사). Spring 컨테이너에서 일치하는 빈으로 만족시킬 수 있는 의존성 수가 가장 많은 생성자가 선택됩니다. 어느 후보도 만족시킬 수 없는 경우에는 primary/기본 생성자(있다면)가 사용됩니다. 마찬가지로, 클래스가 여러 생성자를 선언하지만 그 어떤 생성자도@Autowired로 어노테이션되어 있지 않은 경우에는 primary/기본 생성자(있다면)가 사용됩니다. 클래스가 처음부터 하나의 생성자만 선언하는 경우, 어노테이션 여부와 관계없이 항상 해당 생성자가 사용됩니다. 어노테이션이 붙은 생성자는 public일 필요가 없다는 점에 유의하세요.
또 다른 방법으로, 다음 예제에서 보는 것처럼 Java의 java.util.Optional을 사용하여 특정 의존성이 non-required임을 표현할 수 있습니다:
1public class SimpleMovieLister { 2 3 @Autowired 4 public void setMovieFinder(Optional<MovieFinder> movieFinder) { 5 ... 6 } 7}
또한 파라미터 레벨 @Nullable 어노테이션(어떤 패키지의 어떤 종류든 가능 — 예: JSpecify의 org.jspecify.annotations.Nullable)을 사용하거나 Kotlin의 내장 null-safety 지원을 활용할 수도 있습니다:
1public class SimpleMovieLister { 2 3 @Autowired 4 public void setMovieFinder(@Nullable MovieFinder movieFinder) { 5 ... 6 } 7}
1class SimpleMovieLister { 2 3 @Autowired 4 var movieFinder: MovieFinder? = null 5 6 // ... 7}
또한 BeanFactory, ApplicationContext, Environment, ResourceLoader,
ApplicationEventPublisher, MessageSource와 같은 잘 알려진 resolve 가능한 의존성 인터페이스에도 @Autowired를 사용할 수 있습니다. 이러한 인터페이스 및 ConfigurableApplicationContext나 ResourcePatternResolver와 같은 그 확장 인터페이스는 별도의 설정 없이 자동으로 resolve됩니다. 다음 예제는 ApplicationContext 객체를 자동 주입하는 방법을 보여줍니다:
1public class MovieRecommender { 2 3 @Autowired 4 private ApplicationContext context; 5 6 public MovieRecommender() { 7 } 8 9 // ... 10}
1class MovieRecommender { 2 3 @Autowired 4 lateinit var context: ApplicationContext 5 6 // ... 7}
@Autowired,@Inject,@Value,@Resource어노테이션은 Spring의BeanPostProcessor구현에 의해 처리됩니다. 이는 이러한 어노테이션을 자신의BeanPostProcessor나BeanFactoryPostProcessor타입(있는 경우) 내에서 적용할 수 없다는 의미입니다. 이러한 타입은 XML이나 Spring@Bean메서드를 사용하여 명시적으로 'wired up' 되어야 합니다.
Annotation-based Container Configuration
Fine-tuning Annotation-based Autowiring with @Primary or @Fallback