개발/Spring Framework

[Spring Framework] 의존객체 자동 주입

백괴 2020. 9. 11. 16:14

이전 포스팅에서는, 스프링의 환경설정 파일에 의존 객체를 주입할 경우 <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 객체를 찾아 주입해주었다는 것을 알 수 있습니다.