본문 바로가기
Java/[스프링 5 프로그래밍 입문]

[Spring] 의존 자동 주입(2) - 빈 이름과 한정사

2021. 7. 31.
반응형

스프링에서는 @Autowired 애노테이션을 통해 의존 객체를 자동 주입할 수 있다. 자동 주입할 빈 객체가 존재하지 않거나 하나로 한정되지 않는 경우에 어떤 일이 일어나는지 알아보자. 또한 이런 에러가 발생하면 어떤 방식으로 해결할 수 있을지 알아보자.

 

의존 자동 주입 시 빈 객체를 한정할 수 없는 경우에는 어떻게 될까?

 

[Spring] 의존 자동 주입(1) - @Autowired 애노테이션

이전 포스트에서는 설정 클래스에서 생성자 또는 setter 메서드를 통한 의존 주입 방법을 알아보았다. 이번에는 스프링 프레임워크에서 @Autowired 애노테이션을 이용하여 의존 객체

dct-wonjung.tistory.com

이전 포스트에서 @Autowired 애노테이션을 필드 또는 메서드에 붙여서 의존 객체를 자동 주입하는 방법을 배웠다. 이 방식은 필드의 타입 또는 메서드의 파라미터 타입과 일치하는 타입의 빈 객체를 찾아서 주입하는 원리이다. 그렇다면 일치하는 타입의 빈 객체가 없거나, 여러 개라면 어떻게 될까?

 

일치하는 빈 객체가 없는 경우

@Autowired 애노테이션을 적용한 대상과 일치하는 빈이 없으면 어떻게 되는지 알아보자. 아래는 네 개의 빈 객체를 설정하는 설정 클래스에서 ExDao 타입의 빈 객체를 삭제한 예제이다.

 

public class ExService{

	@Autowired
	private ExDao exDao;
	
}
@Configuration
public class AppCtx {

	//    @Bean
	//    public ExDao exDao(){
	//        return new ExDao();
	//    }
	
	@Bean
	public SampleDao sampleDao(){
		return new SampleDao();
	}
	
	...
}
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'spring.ExService': Unsatisfied dependency expressed through field 'exDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'spring.ExDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...

위와 같은 익셉션이 발생하였다. 이름이 spring.ExService인 빈을 생성하는데 에러가 발생했고, exDao 필드에 대한 의존을 충족하지 않으며 적용할 수 있는 ExDao 타입의 빈이 없다는 내용이 나온다. 이는 설정 클래스 AppCtx의 exDao 필드에 주입할 ExDao 빈이 존재하지 않아서 에러가 발생한 것이다.

 

일치하는 빈이 여러 개인 경우

앞선 경우와는 반대로 주입 대상에 일치하는 빈이 두 개 이상이면 어떻게 되는지 알아보자. 아래는 exDao에 해당하는 빈 설정을 주석으로 막고 exDao1과 exDao2라는 빈 설정을 추가한 코드이다.

@Configuration
public class AppCtx {

	//    @Bean
	//    public ExDao exDao(){
	//        return new ExDao();
	//    }
	
	@Bean
	public ExDao exDao1(){
		return new ExDao ();
	}
	
	@Bean
	public ExDao exDao2(){
		return new ExDao ();
	}
	...
}
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'spring.ExService': Unsatisfied dependency expressed through field 'exDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'spring.ExDao' available: expected single matching bean but found 2: exDao1,exDao2
...

마찬가지로 익셉션이 발생하였다. ExDao 타입의 빈을 한정할 수 없는데, 해당 타입의 빈을 한 개가 아니라 두 개(exDao1, exDao2)를 발견했다는 메시지이다. 자동 주입을 하려면 해당 타입을 가지는 빈이 어떤 빈인지 정확히 한정할 수 있어야 한다. 그러지 않을 경우 스프링은 자동 주입에 실패하고 익셉션을 발생시킨다.

 

 

빈 객체의 한정사

자동 주입 가능한 빈이 두 개 이상이면 자동 주입할 빈을 지정할 수 있는 방법이 필요한데, 이때 사용하는 애노테이션이 @Qualifier이다. @Qualifier 애노테이션을 사용하면 자동 주입할 빈을 한정할 수 있다. 그러면 @Qualifier 애노테이션의 사용 방법을 알아보자.

@Qualifier 애노테이션 사용 방법

첫 번째로 @Qualifier 애노테이션을 사용할 위치는 @Bean 애노테이션을 붙인 빈 설정 메서드이다. 아래는 그 예시이다.

@Configuration
public class AppCtx {
	
	@Bean
	@Qualifier("example")
	public ExDao exDao1(){
		return new ExDao ();
	}
	
	@Bean
	public ExDao exDao2(){
		return new ExDao ();
	}
	...
}

exDao1() 메서드에 "example" 값을 갖는 @Qualifier 애노테이션을 붙여 해당 빈의 한정 값으로 "example"을 지정했다. 이렇게 지정한 한정 값은 자동 주입할 빈을 한정할 때 사용된다.

public class ExService{

	@Autowired
	@Qualifier("example")
	private ExDao exDao;
	
}

위 코드는 example 한정 값을 지정한 빈 객체를 자동 주입하기 위해 @Qualifier 애노테이션을 붙인 예제이다. exDao 필드에 @Autowired를 붙였으므로 ExDao 타입의 빈 객체를 주입하게 되는데, @Qualifier 애노테이션 값이 example이기 때문에 한정 값이 example인 빈을 의존 주입 후보로 사용한다.

 

따라서 앞선 코드에서 @Qualifier 애노테이션 값으로 example을 준 ExDao 타입의 빈 exDao1을 자동 주입 대상으로 사용한다. @Autowired 애노테이션을 필드와 메서드에 모두 적용할 수 있으므로 @Qualifier 애노테이션도 필드와 메서드 모두에 적용할 수 있다.

 

빈 설정에서 @Qualifier를 통해 한정 값을 지정하지 않으면 빈의 이름을 한정사로 지정한다. 따라서 exDao1 빈 객체는 @Qualifier 애노테이션이 붙었으므로 주어진 값인 example이, exDao2 빈 객체는 한정 값을 지정하지 않았으므로 빈의 이름인 exDao2가 한정사가 된다. @Autowired 애노테이션이 붙은 필드나 메서드는 한정 값을 지정해주지 않으면 필드명이나 파라미터명을 한정사로 사용한다.

 

상위/하위 타입 관계와 자동 주입

아래 코드는 ExDao 클래스를 상속한 ExExDao이다. 또한 AppCtx 설정에서 exDao2() 메서드가 ExExDao 타입의 빈 객체를 설정하도록 변경하고 exDao1() 메서드에 붙였던 @Qualifier 애노테이션도 삭제하였다.

public class ExExDao extends ExDao {
	
	@Override
	public void ...
	
}
public class ExService{

	@Autowired
	private ExDao exDao;
	
}
@Configuration
public class AppCtx {
	
	@Bean
	public ExDao exDao1(){
		return new ExDao ();
	}
	
	@Bean
	public ExExDao exDao2(){
		return new ExExDao ();
	}
	...
}

이 상태로 코드를 실행하면 같은 타입의 빈 객체가 두 개 이상일 때와 같은 익셉션이 발생한다. exDao2 빈을 ExExDao 타입으로 변경했음에도 같은 에러가 발생하는 이유는 ExExDao 클래스가 ExDao 클래스를 상속했기 때문이다. ExExDao 클래스는 ExDao 타입에도 할당할 수 있기 때문에 스프링 컨테이너가 ExDao 타입의 빈을 자동 주입해야 하는 곳을 만나면 exDao1 빈과 exDao2 빈 중에서 어떤 빈을 주입해야 할지 알 수 없는 것이다. 따라서 @Qualifier 애노테이션을 이용해 주입할 빈을 한정해주어야 한다.

 

ExService 클래스의 exDao 필드가 ExExDao 타입의 빈 객체를 주입받도록 하는 방법은 두 가지가 있다. 먼저 첫 번째 방법은 exDao2 빈과 이를 사용할 객체에 같은 한정 값을 부여하는 것이다. 아래는 그 예시 코드이다.

public class ExService{

	@Autowired
	@Qualifier("example2")
	private ExDao exDao;
	
}
@Configuration
public class AppCtx {
	
	@Bean
	public ExDao exDao1(){
		return new ExDao ();
	}
	
	@Bean
	@Qualifier("example2")
	public ExExDao exDao2(){
		return new ExExDao ();
	}
	...
}

두 번째 방법은 ExService 클래스의 exDao 필드의 타입을 ExExDao로 변경하는 것이다. ExExDao 타입의 빈은 한 개만 존재하기 때문에 아래의 코드처럼 exDao가 ExExDao 타입의 빈을 자동 주입받도록 하면 자동 주입 대상이 명확해지게 된다.

public class ExService{

	@Autowired
	private ExExDao exDao;
	
}

 

 

 

참고 서적: <초보 웹 개발자를 위한 스프링 5 프로그래밍 입문>

 

초보 웹 개발자를 위한 스프링5 프로그래밍 입문

COUPANG

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

 


Spring Framework 시리즈

  1. 스프링 프로젝트 시작하기 (Maven)
  2. 스프링 컨테이너(Container) 의미
  3. Dependency, DI, Assembler (의존, 의존 주입, 주입기) 개념 정리
  4. 스프링에서의 의존 주입(DI)의 의미와 사용법
  5. 스프링 애노테이션을 사용한 의존 주입(DI)
  6. 의존 자동 주입(1) - @Autowired 애노테이션
728x90
반응형

댓글