[Spring Framework] 의존객체 자동 주입
이전 포스팅에서는, 스프링의 환경설정 파일에 의존 객체를 주입할 경우 <constructor-arg> 태그와 <property> 태그를 이용하였습니다.
하지만, 위와 같이 의존 객체를 명시하지 않아도 스프링 컨테이너가 자동으로 의존 대상 객체를 찾아서 필요한 객체를 주입하는 방법이 존재하는데, 이를 '의존객체 자동주입'이라고 합니다.
이는 @Autowired와 @Resource 어노테이션을 이용해서 쉽게 구현할 수 있습니다.
DI 자동 주입 설정
자동 주입을 사용하기 전, 환경 설정 파일을 건들여줍니다.
기존의 환경설정 파일에 아래의 코드와 같이 <beans> 태그에 '<!-- 추가 -->' 가 붙은 네임스페이스를, 그리고 태그 안에는 <context:annotation-config /> 태그를 추가해줍니다.
해당 요소들을 추가하지 않을 경우 자동 주입을 사용할 수 없습니다.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" <!--추가-->
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context <!--추가-->
http://www.springframework.org/schema/context/spring-context.xsd"> <!--추가-->
<context:annotation-config /> <!--추가-->
</beans>
1. @Autowired
- 1순위로 타입을 통해 의존 대상 객체를 찾습니다.
- 적절한 타입이 없을 경우, 2순위로 이름을 통해 의존 대상 객체를 찾습니다.
- 생성자, 필드, setter 매소드에 사용 가능하며, 필드나 setter 매소드의 경우 디폴트 생성자가 필요합니다.
app_context.xml(환경설정 파일)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<bean id="myprofile" class="MyProfile"></bean>
<bean id="ProfileView" class="ProfileView"></bean>
</beans>
MyProfile.java
public class MyProfile {
public String[] profile = {
"백괴",
"성남시",
"19세"
};
}
ProfileView.java
import org.springframework.beans.factory.annotation.Autowired;
public class ProfileView {
//@Autowired
public MyProfile myprofile;
//디폴트 생성자 (@Autowired를 setter, 필드에서 사용할 때 필요)
public ProfileView() { }
//생성자
@Autowired
public ProfileView(MyProfile myProfile) {
this.myprofile = myProfile;
}
//프로필 출력 메소드
public void view() {
System.out.println("안녕하세요\n저는 " + myprofile.profile[2] + " " +
myprofile.profile[0] + "이구요, " + myprofile.profile[1] + "에 살아요.");
}
//setter
//@Autowired
public void setMyprofile(MyProfile myProfile) {
this.myprofile = myProfile;
}
}
Main.java
import org.springframework.context.support.GenericXmlApplicationContext;
public class Main {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:app_context.xml");
ProfileView pv = ctx.getBean("ProfileView", ProfileView.class);
pv.view();
}
}
위의 예제를 보면, ProfileView 객체에는 생성자에 @Autowired 어노테이션이 있으며, 환경설정 파일에는 <constructor-arg> 태그가 전혀 사용되어있지 않습니다.
하지만 Main 객체를 실행하면 원하는 프로필이 잘 출력되는데요, 그 이유는 @Autowired 어노테이션이 환경설정 파일에서 같은 타입의 의존 대상 객체인 MyProfile 객체를 자동으로 찾아주었기 때문입니다.
앞서 설명드렸듯이, @Autowired 어노테이션은 생성자 이외에도 필드나 setter 매소드에도 사용 가능합니다. 다만, 이 경우 디폴트 생성자를 작성해 주어야 합니다.
@Autowired 어노테이션은 required라는 속성을 사용할 수 있습니다. 속성을 사용하지 않을 경우 디폴트 값은 true이며, false를 지정할 경우 의존 대상 객체가 없어도 예외 처리로 넘어가지 않는다는 점이 있습니다.
@Autowired(required=false)
public void setMyprofile(MyProfile myProfile) {
this.myprofile = myProfile;
}
1-1 @Qualifier 어노테이션을 통한 의존 객체 선택 주입
<bean id="MyProfile1" class="MyProfile"></bean>
<bean id="MyProfile2" class="MyProfile"></bean>
<bean id="MyProfile3" class="MyProfile"></bean>
<!-- 타입 중복 -->
<bean id="ProfileView" class="ProfileView"></bean>
하지만, @Autowired 어노테이션을 사용하면서 위와 같이 환경설정 파일에서 타입이 중복 될 경우 이름으로 찾게 되는데요, 그래도 찾을 수 없을 경우 예외가 발생할 수 있습니다.
이러한 상황에서는 저 셋 중에 하나를 선택해야 할 필요가 있는데요, 이때는 @Qualifier 어노테이션을 사용합니다.
ProfileView.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class ProfileView {
//@Autowired
//@Qualifier("MyProfile1")
public MyProfile myprofile;
//디폴트 생성자
public ProfileView() { }
//생성자
//@Autowired
//@Qualifier 사용 불가능
public ProfileView(MyProfile myProfile) {
this.myprofile = myProfile;
}
//프로필 출력 메소드
public void view() {
System.out.println("안녕하세요\n저는 " + myprofile.profile[2] + " " +
myprofile.profile[0] + "이구요, " + myprofile.profile[1] + "에 살아요.");
}
//setter
@Autowired
@Qualifier("MyProfile1")
public void setMyprofile(MyProfile myProfile) {
this.myprofile = myProfile;
}
}
위 코드의 setter 매소드 부분에 보이듯이, @Qualifier 어노테이션을 사용하실 때 원하는 Bean 객체의 id를 입력해주시면 됩니다.
해당 어노테이션은 setter 매소드와 필드에 사용하실 수 있습니다.
다만, 생성자에서는 사용하실 수 없으니 참고해주시기 바랍니다.
2. @Resource
- @Autowired 어노테이션과는 달리, 1순위로는 매개변수의 이름으로, 2순위로는 타입으로 의존 대상 객체를 결정합니다.
- 생성자에서는 사용할 수 없으며, 필드와 setter 매소드에서만 사용 가능합니다.
app_context.xml(환경설정 파일, 이전과 동일)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<bean id="myprofile" class="MyProfile"></bean>
<bean id="ProfileView" class="ProfileView"></bean>
</beans>
MyProfile.java(이전과 동일)
public class MyProfile {
public String[] profile = {
"백괴",
"성남시",
"19세"
};
}
ProfileView.java
import javax.annotation.Resource;
public class ProfileView {
//@Resource
public MyProfile myprofile;
//디폴트 생성자
public ProfileView() { }
//생성자
public ProfileView(MyProfile myProfile) {
this.myprofile = myProfile;
}
//프로필 출력 메소드
public void view() {
System.out.println("안녕하세요\n저는 " + myprofile.profile[2] + " " +
myprofile.profile[0] + "이구요, " + myprofile.profile[1] + "에 살아요.");
}
//setter
@Resource
public void setMyprofile(MyProfile myProfile) {
this.myprofile = myProfile;
}
}
Main.java(이전과 동일)
import org.springframework.context.support.GenericXmlApplicationContext;
public class Main {
public static void main(String[] args) {
GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:app_context.xml");
ProfileView pv = ctx.getBean("ProfileView", ProfileView.class);
pv.view();
}
}
위의 예제를 보면, 이전과는 달리 이번에는 ProfileView 객체의 setter 매소드에 @Resource 어노테이션이 사용되어 있으며, 실행 시 프로필이 정상적으로 출력됩니다.
앞서 설명드렸다시피, 매개변수의 이름을 통해 의존 대상 객체를 찾아주기 때문에 'myprofile'이라는 이름의 Bean 객체를 찾아 주입해주었다는 것을 알 수 있습니다.