본문 바로가기
Spring|Spring-boot

[Spring] @Autowired , @Qualifier

by oncerun 2020. 6. 18.
반응형

 

 @Autowired는 dependency injection의 xml설정을 대신하는 것입니다.

auto라는 말에 잘못된 이해가 된다면 사용에 따른 문제가 발생할 수 있기에 동작 방식에 대한 이해가 필요합니다.

 

xml에서 설정해준 빈 객체를 가지고 우리는 DI를 처리했습니다.

스프링은 반드시 설정된 정보를 이용해 객체를 생성하고 DI를 해주기 위해 IoC컨테이너를 가지고 있습니다.

 

 

Ioc 컨테이너가 지시서를 읽게되면 지시서대로 객체를 생성하고 인젝션이 일어납니다.

	<bean id="exam" class="spring.NewExam"/>
	<bean id="console" class="spring.InlineExamConsole">
    <property name="exam" ref="exam/>
    </bean>

xml에 설정값입니다. setExam(Exam exam) 메서드를 사용하는데 인자로 exam이름을 같은 빈객체를 주입하도록 되어있습니다.

 

xml설정을 대신해 우리는 setExam메소드에 @Autowried를 사용할 것입니다.

	@Autowired
	public void setExam(Exam exam) {
		
		this.exam = exam;
		
	}

이것은  <property name="exam" ref="exam/> 코드의 내용을 이야기한 것이기 때문에

xml에서 지워보도록 하겠습니다.

	<bean id="exam" class="spring.NewExam"/>
	<bean id="console" class="spring.InlineExamConsole">
    </bean>

 

이제 실행을 시키게 되면 객체가 존재하지 않을 수도 있습니다.  지시서에 객체를 생성하라는 말만 존재하고 설정이 존재한다는 말을 존재하지 않습니다. 그래서 우리는 따로 설정을 해주었습니다

 

<context:annotation-config/> 생성된 객체 안에 annotation을 확인하라는 설정을 해주었습니다.

<context:annotation-config/>
<bean id="exam" class="spring.NewExam"/>
<bean id="console" class="spring.InlineExamConsole">
</bean>

 

컨테이너에서 exam을 찾아서 세팅하게 됩니다.  그런데 뭘 기준으로 객체를 찾을까요?

자료형? 변수명??

먼저 변수명으로 실험을 해보았습니다.

문제없이 잘됩니다.

바로 정답은 자료형입니다.

	@Autowired
	@Override
	public void setExam(Exam exam) {
		
		this.exam = exam;
		
	}

등록된 Bean 객체가 호출될 때  Exam형식을 참조할 수 있는 객체를 자동으로 찾아주고 바인딩을 해준다는 것입니다.

 

만약 참조할 수 있는 Bean객체가 2개가 존재한다면 어떻게 될까요 

바로 에러가 발생합니다.

expected single matching bean but found 2: spring.NewExam#0, spring.NewExam#1

 

console객체에 exam을 주입하는 도중  같은 형식의 두 개의 빈객체가 있어 모호하기에 에러가 발생합니다.

 

만약 변수명과 동일한 이름을 설정해주면 어떻게 될까요? 

 

 

잘되는 것을 확인할 수 있습니다.

 

이러한 빈객체의 id를 가지고 주입될 객체를 정해줄 수 있는 annotation이 @Qualifier입니다.

exam2의 kor속성에 10 이란 값을 넣고 @Qualifier를 exam2로 설정해주었더니 setExam메서드를 실행할 때 id가 exam2의 객체를 주입해준 것을 확인할 수 있습니다.

 

이제는 Autowired가 어떠한 것을 기준으로 꺼내서 인젝션을 해주는지 알 수 있습니다. 바로 자료 형식을 기준으로 하며 식별이 모호할 경우 @Qualifier 가지고 정해줄 수 있다는 것을 알 수 있습니다.

 

 

@Autowierd의 위치

 

 

	@Autowired
    private Exam exam;
	

	@Autowired
	public InlineExamConsole(Exam exam) {
		this.exam = exam;
	}

	@Autowired
	public void setExam(Exam exam) {
		
		this.exam = exam;
		
	}
    

 

@Autowired는 다음과 같은 위치에 올 수 있습니다. 

 

기본 생성자, 오버로드 생성자, setter에서 인젝션을 할 수 있습니다.

 

setter에 @Autowired가 존재한다면 setter메서드가 호출되면서 injection이 발생합니다.

만약 private Exam exam; 에 @Autowired가 존재한다면 기본 생성자를 호출하면서 injection이 발생합니다.

따라서 기본생성자가 존재하지 않고 오버 로드된 생성자만 존재한다면 오류를 발생시킵니다.

만약 생성자가 존재하지 않는다면 컴파일러가 객체를 생성할 때 기본 생성자를 만들어주므로 오류가 발생하지 않습니다.

 

 

    private Exam exam;
	
    public InlineExamConsole(){
    }

	@Autowired
	public InlineExamConsole(@Qualifier("exam1")Exam exam1,
    				@Qualifier("exam2")Exam exam2) {
		this.exam = exam;
	}

	public void setExam(Exam exam) {
		
		this.exam = exam;
		
	}
    

만약 오버 로드된 생성자에 @Qualifier를 지정하면 오류가 발생합니다. 오버로드된 생성자에는 Exam형식의 객체가 여러 개가 올 수 있다고 판단하기 때문에 파라미터 값에 직접적으로 설정해주어야 합니다.

 

따라서 내가 어떠한 함수가 실행되면서 Injection 되길 바라는 가에 따라 위치를 적절하게 고르면 됩니다.

 

옵션 중 required라는 옵션이 존재합니다. @Autowired는 자동적으로 빈객체를 주입하는데 만약 빈객체가 존재하지 않을 경우에 무조건적으로 에러를 발생시킵니다. null값을 원할 경우에 취할 수 있는 옵션으로 

@Autowired(required = false)로 분기를 만들 수 있습니다.

 

 

반응형

'Spring|Spring-boot' 카테고리의 다른 글

[Spring] Java Configuration  (0) 2020.06.22
[Spring] @Component  (0) 2020.06.22
[Spring] Annotaion  (0) 2020.06.18
[Spring] 생성자 DI  (0) 2020.06.17
[Spring] 값 형식 DI  (0) 2020.06.17

댓글