1. 개요

Spring 2.5부터 프레임워크는 어노테이션 기반 의존성 주입 을 도입 했습니다. 이 기능의 주요 어노테이션은 @Autowired 입니다. 이를 통해 Spring은 협업 빈을 해결하고 우리 빈에 주입할 수 있습니다.

이 예제에서는 먼저 자동 연결을 활성화하는 방법과 Bean을 자동 연결 하는  다양한 방법을 살펴보겠습니다 . 나중에 @Qualifier 어노테이션을 사용하여 빈 충돌을 해결하는 방법 과 잠재적인 예외 시나리오 에 대해 이야기하겠습니다 .

2. @Autowired 어노테이션 활성화

Spring 프레임워크는 자동 의존성 주입을 가능하게 합니다. 즉, Spring 구성 파일에서 모든 bean 의존성을 선언함으로써 Spring 컨테이너는 협력 bean 간의 관계를 자동으로 연결할 수 있습니다 . 이것을 Spring bean autowiring 이라고 합니다.

애플리케이션에서 Java 기반 구성을 사용하려면 어노테이션 기반 주입 을 활성화하여  Spring 구성을 로드합니다.

@Configuration
@ComponentScan("com.baeldung.autowire.sample")
public class AppConfig {}

또는 <context:annotation-config> 어노테이션은 주로 Spring XML 파일에서 의존성 주입 어노테이션을 활성화하는 데 사용됩니다.

또한 Spring Boot는 @SpringBootApplication 어노테이션 을 도입합니다 . 이 단일 어노테이션은 @Configuration , @EnableAutoConfiguration 및  @ComponentScan 을 사용하는 것과 동일합니다 .

애플리케이션의 기본 클래스에서 이 어노테이션을 사용해 보겠습니다.

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

결과적으로 이 Spring Boot 애플리케이션을 실행 하면 현재 패키지 및 해당 하위 패키지의 구성 요소를 자동으로 스캔합니다 . 따라서 Spring의 애플리케이션 컨텍스트에 등록하고 @Autowired 를 사용하여 빈을 주입할 수 있습니다.

3. @Autowired 사용

어노테이션 삽입을 활성화한 후 속성, 설정자 및 생성자에서 자동 연결을 사용할 수 있습니다 .

3.1. 속성의 @Autowired

@Autowired 를 사용하여 속성에 어노테이션을 추가하는 방법을 살펴보겠습니다 . 이렇게 하면 getter 및 setter가 필요하지 않습니다.

먼저 fooFormatter 빈을 정의해 보겠습니다.

@Component("fooFormatter")
public class FooFormatter {
    public String format() {
        return "foo";
    }
}

그런 다음 필드 정의에서 @Autowired 를 사용하여 이 빈을 FooService 빈 에 주입합니다 .

@Component
public class FooService {  
    @Autowired
    private FooFormatter fooFormatter;
}

결과적으로 Spring은 FooService 가 생성 될 때 fooFormatter 를 주입합니다.

3.2. 세터에서 @Autowired

이제 setter 메서드에 @Autowired 어노테이션을 추가해 보겠습니다 .

다음 예제에서는 FooService 가 생성 될 때 FooFormatter 의 인스턴스와 함께 setter 메서드가 호출됩니다.

public class FooService {
    private FooFormatter fooFormatter;
    @Autowired
    public void setFormatter(FooFormatter fooFormatter) {
        this.fooFormatter = fooFormatter;
    }
}

3.3. @Autowired on 생성자

마지막으로 생성자에서 @Autowired 를 사용합시다.

FooFormatter 의 인스턴스가 FooService 생성자 에 대한 인수로 Spring에 의해 주입되는 것을 볼 수 있습니다.

public class FooService {
    private FooFormatter fooFormatter;
    @Autowired
    public FooService(FooFormatter fooFormatter) {
        this.fooFormatter = fooFormatter;
    }
}

4. @Autowired 및 선택적 의존성

bean이 구성될 때 @Autowired 의존성을 사용할 수 있어야 합니다. 그렇지 않으면 Spring이 연결을 위해 빈을 해결할 수 없으면 예외가 발생 합니다.

따라서 다음 형식을 제외하고는 Spring 컨테이너가 성공적으로 시작되지 않습니다.

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [com.autowire.sample.FooDAO] found for dependency: 
expected at least 1 bean which qualifies as autowire candidate for this dependency. 
Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true)}

이 문제를 해결하려면 필요한 유형의 빈을 선언해야 합니다.

public class FooService {
    @Autowired(required = false)
    private FooDAO dataAccessor; 
}

5. Autowire 명확화

기본적으로 Spring 은 유형별 로 @Autowired 항목을 해결합니다. 컨테이너에서 동일한 유형의 두 개 이상의 빈이 사용 가능한 경우 프레임워크는 치명적인 예외를 발생 시킵니다.

이 충돌을 해결하려면 주입하려는 Bean을 Spring에 명시적으로 알려야 합니다.

5.1. @Qualifier 에 의한 자동 연결

예를 들어 @Qualifier 어노테이션을 사용하여 필요한 빈을 표시하는 방법을 살펴보겠습니다 .

먼저 Formatter 유형의 빈 2개를 정의합니다 .

@Component("fooFormatter")
public class FooFormatter implements Formatter {
    public String format() {
        return "foo";
    }
}
@Component("barFormatter")
public class BarFormatter implements Formatter {
    public String format() {
        return "bar";
    }
}

이제 Formatter 빈을 FooService 클래스 에 주입해 봅시다 .

public class FooService {
    @Autowired
    private Formatter formatter;
}

이 예제 에는 Spring 컨테이너에 사용할 수 있는 Formatter 의 두 가지 구체적인 구현이 있습니다. 결과적으로 Spring은 FooService 를 구성할 때 NoUniqueBeanDefinitionException 예외를 발생시킵니다 .

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: 
No qualifying bean of type [com.autowire.sample.Formatter] is defined: 
expected single matching bean but found 2: barFormatter,fooFormatter

@Qualifier 어노테이션 을 사용하여 구현 범위를 좁히면 이를 피할 수 있습니다 .

public class FooService {
    @Autowired
    @Qualifier("fooFormatter")
    private Formatter formatter;
}

동일한 유형의 여러 빈이 있는 경우 모호성을 피하기 위해 @Qualifier 를 사용 하는 것이 좋습니다 .

@Qualifier 어노테이션 의 값은 FooFormatter 구현 의 @Component 어노테이션에 선언된 이름과 일치합니다 .

5.2. Custom Qualifier에 의한 Autowiring

Spring은 또한 우리가 커스텀 @Qualifier 어노테이션 을 생성할 수 있게 해줍니다 . 이렇게 하려면 정의와 함께 @Qualifier 어노테이션을 제공해야 합니다.

@Qualifier
@Target({
  ElementType.FIELD, ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface FormatterType {  
    String value();
}

그런 다음 다양한 구현 내에서 FormatterType  을 사용하여 사용자 지정 값을 지정할 수 있습니다.

@FormatterType("Foo")
@Component
public class FooFormatter implements Formatter {
    public String format() {
        return "foo";
    }
}
@FormatterType("Bar")
@Component
public class BarFormatter implements Formatter {
    public String format() {
        return "bar";
    }
}

마지막으로 사용자 지정 Qualifier 어노테이션을 autowiring에 사용할 준비가 되었습니다.

@Component
public class FooService {  
    @Autowired
    @FormatterType("Foo")
    private Formatter formatter;
}

@Target 메타 어노테이션 에 지정된 값 은 한정자를 적용할 위치를 제한합니다. 이 예에서는 필드, 메서드, 유형 및 매개변수입니다.

5.3. 이름으로 자동 연결

Spring은 bean의 이름을 기본 한정자 값으로 사용합니다. 컨테이너를 검사하고 autowire 속성으로 정확한 이름을 가진 bean을 찾습니다.

따라서 우리의 예에서 Spring은 fooFormatter 속성 이름을 FooFormatter 구현에 일치시킵니다. 따라서 FooService 를 구성할 때 특정 구현을 주입합니다 .

public class FooService {
 @Autowired 
private Formatter fooFormatter; 
}

6. 결론

이 기사에서 우리는 autowiring과 그것을 사용하는 다양한 방법에 대해 논의했습니다. 또한 누락된 빈 또는 모호한 빈 주입으로 인해 발생하는 두 가지 일반적인 자동 연결 예외를 해결하는 방법을 조사했습니다.

이 기사의 소스 코드는 GitHub 프로젝트 에서 사용할 수 있습니다 .

Generic footer banner