2023. 10. 18. 23:10ㆍ학부 강의/웹프로그래밍 (Spring)
0. 출처
아직 배우고 있는 중이라 부정확한 정보가 포함되어 있을 수 있습니다!
주의하세요!
올인원 스프링 프레임워크 참고.
1. 문제 발생
앞서 의존 객체 자동 주입_1에서 의존 객체를 자동으로 주입해 보았다.
앞선 글에 사용한 예제는 아주 단순하기 때문에 아무런 문제 없이 의존 객체를 자동으로 주입할 수 있었다.
하지만 조금만 코드가 복잡해지면 의존 객체가 자동으로 주입되지 않을 수 있다.
예를 들어 만약 생성자가 여러 개 오버로딩되어 있다면 어떨까?
가. 수동 주입
<bean id="registerService" class="ch05_pjt_01.contact.service.ContactRegisterService">
<constructor-arg ref="contactDao"/>
</bean>
의존 객체를 자동으로 주입하기 이전에는 <constructor-arg>
를 가지고서 어떤 생성자를 사용할지 판단할 수 있었다.
나. 자동 주입
하지만 자동으로 주입하는 경우는 조금 다르다.
지난 시간에 사용한 예제를 보자.
package ch05_pjt_01.contact.service;
import ch05_pjt_01.contact.ContactSet;
import ch05_pjt_01.contact.dao.ContactDao;
public class ContactRegisterService {
private ContactDao contactDao;
public ContactRegisterService(ContactDao contactDao) {
this.contactDao = contactDao;
}
public void register(ContactSet contactSet) {
String name = contactSet.getName();
if(verify(name)){
contactDao.insert(contactSet);
}else {
System.out.println("The name has already regiseterd.");
}
}
public boolean verify(String name){
ContactSet contactSet = contactDao.select(name);
return contactSet == null ? true : false;
}
public void SetWordDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
}
<bean id="registerService" class="ch05_pjt_01.contact.service.ContactRegisterService"/>
registerService
bean은 의존 객체를 자동으로 주입하게 되면서 <constructor-arg ref="contactDao"/>
를 생략했다.
만약 이 상태에서 또 다른 생성자를 추가하면 어떻게 될까?
public ContactRegisterService(){}
이제 어떤 생성자를 사용해서 의존객체를 생성할지 판단할 수 없게 된다.
이런 문제를 해결하기 위해서 @Autowired
, @Resource
, @Inject
를 사용한다.
2. @Autowired
가. 생성자에 연결
import org.springframework.beans.factory.annotation.Autowired;
...
public ContactRegisterService(){}
@Autowired
public ContactRegisterService(ContactDao contactDao){
this.contactDao = contactDao;
}
@Autowired
는 실행에 필요한 객체를 데이터 타입을 바탕으로 스스로 추측하여 주입한다.
즉, ContactRegisterService
객체가 생성될 때 필요한 ContactDao
객체를 데이터 타입을 바탕으로 판단하여 주입한다.
@Autowired
는 생성자 외에도 필드와 메서드에도 사용할 수 있다.
나. 필드에 연결
import org.springframework.beans.factory.annotation.Autowired;
...
@Autowired
private ContactDao contactDao;
public ContactRegisterService(){}
//@Autowired
//public ContactRegisterService(ContactDao contactDao){
// this.contactDao = contactDao;
//}
디폴트 생성자에 의해서 ContactRegisterService
가 생성되고 @Autowired
한 contactDao는 자동 주입된다.
직관적이기 때문에 가장 많이 사용된다.
다. 메서드, setter에 연결
import org.springframework.beans.factory.annotation.Autowired;
...
//@Autowired
//private ContactDao contactDao;
//public ContactRegisterService(){}
//@Autowired
//public ContactRegisterService(ContactDao contactDao){
// this.contactDao = contactDao;
//}
@Autowired
public void setContactDao(ContactDao contactDao){
this.contactDao = contactDao;
}
라. 주의점
@Autowired
필드 또는 메서드에 적용할 때는 반드시 디폴트 생성자가 필요한다.@Autowired
는 객체 생성에 필요한 객체를 데이터 타입을 바탕으로 스스로 추측하여 주입한다. 이때 같은 데이터 타입을 가진 bean이 여러 개 있는 경우 문제가 된다. 즉,ContactRegisterService
객체가 생성될 때 필요한ContactDao
객체를 데이터 타입을 바탕으로 판단하는데ContactDao
타입을 사용하는contactDao1
,contactDao2
가 있을 경우 둘 중 어느 것을 주입할 지 판단할 수 없다. (해결법은 아래에)
3. @Resource
@Resource
도 @Autowired
와 비슷하다.
@Resource
를 사용해서 의존 객체를 자동으로 주입받을 수 있다.
이때 다른 점은 다음과 같다.
@Autowired | @Resource | |
의존 객체 탐색 방법 | 데이터 타입 바탕 | 빈 객체의 이름 |
적용 대상 | 생성자, 필드, 메서드 | 필드, 메서드 |
annotation 제공 | spring | java |
@Autowired
와 다르게 빈 객체의 이름을 바탕으로 객체를 탐색해서 주입한다.
또한 생성자에 연결할 수 없고 오직 필드와 메서드에만 사용할 수 있다.
spring이 아닌 java에서 제공하는 annotation임으로 spring을 사용하지 않는 java 프로젝트에서도 사용할 수 있다.
단, spring에서 @Resouce
를 사용하려면 pom.xml에 빌드 설정을 추가해야 한다.
<!-- pom.xml에 추가-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotaion-api</artifactId>
<version>1.3.2</version>
</dependency>
가. 필드에 연결
import javax.annotation.Resource;
@Resouce
private ContactDao contactDao;
appCtx.xml
에서 contactDao
라는 이름을 가진 bean을 주입한다.
나. 메서드에 연결
import javax.annotation.Resource;
private ContactDao contactDao;
@Resource
public void setContactDao(ContactDao contactDao){
this.contactDao = contactDao;
}
다. 주의점
- 생성자에 연결할 순 없다.
@Resource
는 스프링이 아닌 자바 자체의 annotation이다. → Maven 설정 파일 pom.xml에 설정을 추가해야 함.
4. @Qualifier
ContactDao
타입을 사용하는 bean이 여러 개 있다고 가정해 봅시다.
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao3" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="registerService" class="ch05_pjt_01.contact.service.ContactRegisterService" />
@Autowired
와 @Resource
모두 @Qualifier
를 사용해서 주입할 bean을 명시적으로 지정할 수 있다.
이를 통해서 @Autowired
와 @Resource
가 가진 문제를 해결할 수 있다.
가. @Autowired의 경우
@Autowired
는 객체 생성에 필요한 객체를 데이터 타입을 바탕으로 스스로 추측하여 주입한다.
이때 같은 데이터 타입을 가진 bean이 여러 개 있는 경우 문제가 된다.
즉, ContactRegisterService
객체가 생성될 때 필요한 ContactDao
객체를 데이터 타입을 바탕으로 판단하는데 ContactDao
타입을 사용하는 contactDao1
, contactDao2
, contactDao3
가 있을 경우 어느 것을 주입할지 판단할 수 없다.
이때 @Qualifier
를 사용해서 주입할 bean을 명시적으로 지정할 수 있다.
이를 통해서 @Autowired
가 가진 문제를 해결할 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@Autowired
@Qualifier("usedDao")
private ContactDao contactDao;
ContactDao
데이터 타입을 사용하면서 Qualifier가 usedDao
인 것을 골라서 주입한다.
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" >
<qualifier value="usedDao"/>
<bean/>
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao3" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="registerService" class="ch05_pjt_01.contact.service.ContactRegisterService" />
contactDao1
가 qualifier가 usedDao
기 때문에 주입된다.
나. @Resource의 경우
@Resource
는 bean의 이름을 바탕으로 객체를 탐색해서 주입한다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@Resource
private ContactDao contactDao;
contactDao1
, contactDao2
, contactDao3
은 있지만 contactDao
라는 이름의 bean이 없다.
그래서 주입할 객체를 찾을 수 없는 문제가 있다.
이때 @Resource
도 @Qualifier
를 사용해서 주입할 bean을 명시적으로 지정할 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@Resource
@Qualifier("usedDao")
private ContactDao contactDao;
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" >
<qualifier value="usedDao"/>
<bean/>
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao3" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="registerService" class="ch05_pjt_01.contact.service.ContactRegisterService" />
이를 통해서 @Autowired
와 @Resource
가 가진 문제를 해결할 수 있다.
다. @Qualifier를 생략 가능한 경우
bean id와 같은 이름을 사용하는 경우 @Qualifier
를 생략할 수 있다.
<bean id="contactDao" class="ch05_pjt_01.contact.dao.ContactDao" /> // 수정
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao3" class="ch05_pjt_01.contact.dao.ContactDao" />
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@Resource 또는 @Autowired
//@Qualifier("usedDao") 생략 가능
private ContactDao contactDao;
라. 매개변수 개수가 2개 이상인 경우
public class Example{
@Autowired
public Example(@Qualifier("hello") FirstBean fBean, @Qualifier("world") SecondBean sBean) { ... }
5. @Inject
@Autowired
와 기능적으로 유사하지만, @Inject
도 @Resource
처럼 Java의 javax.inject
패키지에서 제공하는 애노테이션이다.
기능적으로 유사하다는 것은 생성자, 필드, 메서드에 사용할 수 있고 데이터 타입을 바탕으로 주입할 객체를 탐색한다는 의미다.
주의점! @Inject
도 @Autowired
와 같이 필드 또는 메서드에 적용할 때는 반드시 디폴트 생성자가 필요하다.
단, @Inject
는 @Autowired
와 달리 required
속성을 지원하지 않는다.
@Autowired
에는 의존 객체 주입 시 필수 여부를 지정할 수 있는 @Autowired(required = false)
와 같은 속성이 있다.
@Resource
처럼 Java의 javax.inject
패키지를 pom.xml에 추가해야 한다.
<!-- pom.xml에 추가-->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
가. @Named
@Autowired
가 같은 데이터 타입을 가진 bean이 여러 개 있는 경우 발생하는 문제를 @Qualifier
로 풀었다면 @Inject
는 @Named
로 풀 수 있다.
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao3" class="ch05_pjt_01.contact.dao.ContactDao" />
@Inject
@Named("contactDao1")
private ContactDao contactDao;
6. 정리
Autowired | Inject | Resource | |
탐색 방법 | 데이터 타입 | 데이터 타입 | bean id, 이름 |
범위 | 생성자, 필드, 메서드 | 생성자, 필드, 메서드 | 필드, 메서드 |
spring? java? | spring | java | java |
주입할 bean을 지정하는 법 | @Qualifier | @Named | @Qualifier |
기타 | required 속성 사용 가능 | required 속성 사용 불가능 |
'학부 강의 > 웹프로그래밍 (Spring)' 카테고리의 다른 글
[Spring] STS, Tomcat (1) | 2023.10.28 |
---|---|
[Spring] @Configuration로 Bean 생성하기 (0) | 2023.10.18 |
[Spring] 의존 객체 자동 주입_1 (0) | 2023.10.07 |
[Spring] Spring Bean Scope (0) | 2023.10.07 |
[Spring] 학사 정보 시스템 (0) | 2023.10.07 |