본문 바로가기

Spring

[Spring] 의존객체 자동 주입 (@Autowired, @Resource) & 의존객체 선택 주입 (@Inject, @Qualifier)

[해당 포스트는 개인적으로 공부를 하고 차후에 참고용으로 하고자 작성한 것입니다.
따라서 잘못된 부분이나 부족한 부분이 있을 수 있기에 참고하시기 바랍니다.]

이전 포스팅에서 Spring 설정 파일에 의존 객체를 주입할 때 <constructor-org> 태그 또는 <property> 태그를 이용하여 주입하였다. 이번 포스팅에선 위의 태그로 의존 대상 객체를 명시하지 않아도 Spring Container가 자동으로 필요한 의존 대상 객체를 찾아서 의존 대상 객체가 필요한 객체에 주입하는 방법에 대해 설명하도록 하겠다.

 

의존객체자동주입

@Autowired

주입하려고 하는 '객체의 타입'이 일치하는 객체를 자동으로 주입한다.

<context:annotation-config/> 태그 속성을 이용하여 Spring에서 제공하는 Annotation을 이용할 수 있다.

 

Default application-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<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>

 

생성자 쪽에서 단순히 @Autowired를 입력하면  Application Container에 존재하는 Bean의 Type과 동일한 객체를 자동 주입이 가능하다.

 

WordDao와 WordRegisterService 객체를 다음과 같이 Bean으로 등록한다.

 

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<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="wordDao" class="com.word.dao.WordDao" />

	<bean id="wordService"
		class="com.word.service.WordRegisterService">
	</bean>
</beans>

 

WordDao.java

package com.word.dao;

public class WordDao {
	
	private String value;

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}	
}

 

단순히 String 값을 저장할 수 있도록 Getter와 Setter를 생성한다.

 

WordRegisterService.java

package com.word.service;

import org.springframework.beans.factory.annotation.Autowired;

import com.word.dao.WordDao;

public class WordRegisterService {
	
	WordDao dao;
	
	@Autowired
	public WordRegisterService(WordDao dao) {
		this.dao = dao;
	}
	
	public void setValue(String value) {
		dao.setValue(value);
	}
	
	public String getValue() {
		return dao.getValue();
	}
}

 

생성자에서는 WordDao 객체 정보를 받아와 저장한다. 이전 포스팅에선 application-context.xml 파일에 <constructor-org> 태그를 명시하여 주입하였다.

자동 주입은 별도로 xml파일에 명시할 필요 없이 @Autowired를 통해 WordDao의 객체 타입과 일치하는 Bean을 자동으로 주입한다.

 

MainClass.java

 

package com.word;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.word.service.WordRegisterService;

public class MainClass {

	public static void main(String[] args) {
		
		GenericXmlApplicationContext container = 
				new GenericXmlApplicationContext("classpath:appCtxUseAutowired.xml");
		
		WordRegisterService service =
				container.getBean("wordService", WordRegisterService.class);
		
		service.setValue("setValue");
		System.out.println(service.getValue());
	}
}

 

결과 화면

 

 

프로젝트가 성공적으로 돌아가는 것을 확인할 수 있다.

 

생성자에 @Autowired를 사용할 수 있을 뿐만 아니라, 일반 필드 변수나 메서드에서도 사용이 가능하다.

단 주의해야 할 점이 생성자가 오버로딩 되어있을 경우엔 Default 생성자가 존재해야 한다.

 

에러발생!

public class WordRegisterService {
	
	@Autowired
	WordDao dao;
	
	public WordRegisterService(WordDao dao) {
		this.dao = dao;
	}
}

 

정상작동

public class WordRegisterService {
	
	@Autowired
	WordDao dao;
}

 

public class WordRegisterService {
	
	WordDao dao;

	@Autowired
	public WordRegisterService(WordDao dao) {
		this.dao = dao;
	}
}

 

public class WordRegisterService {
	
	@Autowired
	WordDao dao;
	
	public WordRegisterService() {
		
	}
	
	public WordRegisterService(WordDao dao) {
		this.dao = dao;
	}
}

 

* 참고

@Autowired(required = false) 를 이용하여 Bean에 객체가 등록되지 않은 상태에서 실행할 때 에러가 발생하지 않도록 방지할 수 있다. 원래는 자동 주입이 돼야 하지만 required 속성을 통해 Bean이 존재하지 않으면 자동 주입시키지 않는다.

 

@Resource

주입하려고 하는 '객체의 이름'이 일치하는 객체를 자동으로 주입한다.

@Autowired와의 차이점을 보자면 객체의 타입이 아니라 객체의 이름이 일치해야 한다.

또한 @Resource는 생성자에서 호출할 수 없기 때문에, 필드 변수에서 사용이 가능하다.

 

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<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="wordDao" class="com.word.dao.WordDao" />

	<bean id="wordService"
		class="com.word.service.WordRegisterService">
	</bean>
</beans>

 

여기서 주목해야 할 것은 WordDao Bean의 id 값이다.

Resource를 통해 자동 주입을 하려면, 주입하려는 Class에서 Bean의 id이름과 동일해야 한다.

 

WordRegisterService.java

package com.word.service;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;

import com.word.dao.WordDao;

public class WordRegisterService {
	
	@Resource
	WordDao wordDao;
	
	public void setValue(String value) {
		wordDao.setValue(value);
	}
	
	public String getValue() {
		return wordDao.getValue();
	}
}

 

Resource는 생성자가 필요 없이 자동 주입이 되기 때문에 생성자를 생략할 수 있다.

 

결과는 @Autowired와 동일하다.

 

의존객체선택주입

다수의 Bean객체 중 의존 객체의 대상이 되는 객체를 선택하여 사용할 수 있다.

동일한 객체가 2개 이상인 경우 Spring Container는 자동 주입 대상 객체를 판단하지 못해 Exception을 발생시킨다.

 

@Inject

@Autowired와 거의 비슷하게 @Injection Annotation을 이용해서 의존 객체를 주입할 수 있다. 차이점이라면 @Inject의 경우 required 속성을 지원하지 않는다.

대신 주입되어야 하는 의존성에 검증된 이름을 사용하고자 할 때 @Named를 사용할 수 있다.

 

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<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="wordDao1" class="com.word.dao.WordDao" />
	<bean id="wordDao2" class="com.word.dao.WordDao" />
	<bean id="wordDao3" class="com.word.dao.WordDao" />

	<bean id="wordService"
		class="com.word.service.WordRegisterService">
	</bean>
</beans>

 

위와 같이 WordDao Type의 Bean이 3개가 존재한다고 하자. Autowired의 경우 동일한 Type의 객체를 가져오기 때문에 3개 모두 똑같으면 어떤 걸 가져와야 하는지 모르기 때문에 에러가 발생한다.

@Inject는 @Named와 주로 같이 사용한다. @Named를 이용하여 동일한 Type의 Bean의 id를 통해 식별할 수 있다.

 

public class WordRegisterService {
	
	WordDao dao;
	
	@Inject
	public WordRegisterService(@Named("wordDao1") WordDao dao) {
		this.dao = dao;
	}
	
	public void setValue(String value) {
		dao.setValue(value);
	}
	
	public String getValue() {
		return dao.getValue();
	}
}

 

이럴 경우 dao는 WordDao1 을 식별하고 해당 Bean을 사용하게 된다.

 

@Qualifier

Bean 생성 시 Qualifier를 통해 Bean id를 명시시킬 수 있다.

application-context.xml 에서 bean을 생성할 때 다음의 태그를 같이 추가한다.

 

<qualifier value="name"/>

 

단 생성자에서는 선언할 수 없으며 필드 변수에서 선언이 가능하다.

 

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<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="wordDao1" class="com.word.dao.WordDao">
		<qualifier value="usedDao" />
	</bean>
	<bean id="wordDao2" class="com.word.dao.WordDao" />
	<bean id="wordDao3" class="com.word.dao.WordDao" />

	<bean id="wordService"
		class="com.word.service.WordRegisterService">
	</bean>
</beans>

 

WordDao의 Bean이 여러 개 선언한 걸 알 수 있다. 이것을 선택하여 사용할 수 있도록 qualifier를 명시한다.

 

WordRegisterService.java

public class WordRegisterService {
	
	@Autowired
	@Qualifier("usedDao")
	WordDao dao;
	
	public void setValue(String value) {
		dao.setValue(value);
	}
	
	public String getValue() {
		return dao.getValue();
	}
}

 

@Qualifier를 통해 application-context.xml에서 명시했던 qualifier 이름을 넣으면 동일한 Type의 Bean들 중 해당 Bean을 선택하여 주입이 된다.