@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 |
댓글