Spring & Springboot/올인원 스프링 프레임워크

스마트폰 연락처 -2

YJ_ma 2023. 9. 19. 11:49

@Autowired를 이용한 의존 객체 자동 주입

생성자가 여러 개인 경우

Serivce빈이 생성될 때 생성자에 ContactDao가 자동 주입되는 것을 확인했다.

 

만약 새성자가 오버라이드되어 여러 개가 있다면 어떻게 될까?

이를 확인하기 위해 Service클래스에 디폴트 생성자를 추가하고 실행해보면 다음과 같다.

■ ContactRegisterService 클래스 생성자

public ContactRegisterService() {
    System.out.println("default constructor");
}

public ContactRegisterService(ContactDao contactDao) {
    System.out.println("contactDao: " + contactDao);
    this.contactDao = contactDao;
}

■ ContactSearchService 클래스 생성자

public ContactSearchService() {
    System.out.println("default constructor");
}

public ContactSearchService(ContactDao contactDao) {
    System.out.println("contactDao: " + contactDao);
    this.contactDao = contactDao;
}

실행 결과

이처럼 디폴트(defualt) 생성자가 추가된 클래스가 실행되는 것을 확인할 수 있다.

→ appCtx.xml에서 <bean>태그에 <constructor-arg/>을 사용하지 않았기 때문이다.

 

이렇게 오버라이드된 경우 CantactDao가 Service 객체에 자동 주입되게 하려면 @Autowired 애너테이션을 명시하면 된다.

 @Authowired 애너테이션은 생성자 또는 메서드에 주입하면 된다.

·  생성자에 주입하는 경우

@Autowired
public ContactSearchService(ContactDao contactDao) {
    System.out.println("contactDao: " + contactDao);
    this.contactDao = contactDao;
}

 

·  필드에 주입하는 경우

@Autowired
private ContactDao contactDao;

 

· 메서드에 주입하는 경우

@Autowired
public void setWordDao(ContactDao contactDao) {
    this.contactDao = contactDao;
}

 

@Resource를 이용한 의존 객체 자동 주입

@Autowired와 @Resource의 차이점

@Autowired @Resource
· 데이터 타입을 이용한 의존 객체 자동 주입
· 필드, 생성자, 메서드, 사용 가능
· 빈 객체의 이름을 이용한 의존 객체 자동 주입
· 필드, 메서드에 사용 가능(생성자 사용 불가능)

 

@Resource 적용 대상

필드에 @Resource 적용

- @Resource : @Autowired와 달리 스프링이 아닌 자바에서 제공하는 애너테이션으로 관련 모듈을 pom.xml에 설정해야한다.

- javax.annotation-api 모듈을 pom.xml에 추가한다.

1. 메인 레포지토리에 접속하여 javax.annotation-api 모듈을 검색 후 Javax Annotation API를 선택한다.

2. Javax AnnotationAPI 페이지에서 1.3.2를 클릭한다. 클릭 후 나온 페이지에서 메이븐 코드를 복사한다.

3. 복사한 코드를 pom.xml에 붙여넣는다.

<!-- spring-context 모듈 -->
  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
	<dependency>
	    <groupId>javax.annotation</groupId>
	    <artifactId>javax.annotation-api</artifactId>
	    <version>1.3.2</version>
	</dependency>

  </dependencies>

javax.annotation-api를 추가했다면 @Resource를 이용해서 ContactRegisterService와 ContactSearchService에서 ContactDao를 필드에 자동 주입한다.

 

■ ContactRegisterService와 ContactSearchService 클래스

이때 앞에서 작성한 @Autowired는 주석처리하고 다음과 같이 수정해준다.

import javax.annotation.Resource;

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

import ch05_pjt_01.contact.ContactSet;
import ch05_pjt_01.contact.dao.ContactDao;

public class ContactRegisterService {
	@Resource
	private ContactDao contactDao;

실행결과

메서드에 @Resource 적용

· @Resource를 메서드에 적용할 수 있다. 

· ContactRegisterService와 ContactSearchService의 setter 메서드에 적용한다.

 

■ ContactRegisterService와 ContactSearchService 클래스

@Resource
public void setWordDao(ContactDao contactDao) {
    this.contactDao = contactDao;
}

실행결과

실행결과와 같이 ContactDao 객체가 setContactDao() 메서드에 자동 주입되어 정상 실행되었음을 알 수 있다.

@Resource는 생성자에 적용할 수 없다!!

 

다수의 빈 객체 중 의존 대상 객체 선택 방법

📣 만약 자동 주입 대상 객체가 2개 이상이면 어떻게 될까?

자동 주입 대상 객체가 2개 이상인 경우

다음과 같이 3개 (contactDao1, contactDao2, contactDao3)의 DAO 객체가 있다면 에러가 발생한다.

<bean id="contactDao" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />

에러 발생 : 의존 객체 자동으로 주입 실패

@Autowired는 객체 타입을 찾아서 자동으로 의존 객체를 주입한다.

따라서 동일한 타입의 의존 객체가 2개 이상인 경우에는 어떤 의존 객체를 자동 주입해야 하는지 판단할 수 없다.

이런경우 의존 대상 객체를 개발자가 지정해주면 된다.

<bean id="contactDao" class="ch05_pjt_01.contact.dao.ContactDao">
    <qualifier value="usedDao"/>
</bean>
<bean id="contactDao1" class="ch05_pjt_01.contact.dao.ContactDao" />
<bean id="contactDao2" class="ch05_pjt_01.contact.dao.ContactDao" />

<qualifier> 태그 : 의존 대상 객체로 지정한다.

appCtx.xml에 <qualifier> 태그를 추가했다면 의존 객체가 자동 주입되는 ContactRegisterService와 ContactSearchService에 @Qualifier 애너테이션을 추가해주어야 한다. 

이때 @Autowired와 @Resource 중 어느 쪽을 사용해도 상관없다.

 

■ @Autowired와 @Qualifier를 이용한 특정 의존 객체 지정

package ch05_pjt_01.contact.service;

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

import ch05_pjt_01.contact.ContactSet;
import ch05_pjt_01.contact.dao.ContactDao;

public class ContactSearchService {
	@Autowired
	@Qualifier("usedDao")
	private ContactDao contactDao;

 

■ @Resource와 @Qualifier를 이용한 특정 의존 객체 지정

package ch05_pjt_01.contact.service;

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

import ch05_pjt_01.contact.ContactSet;
import ch05_pjt_01.contact.dao.ContactDao;

public class ContactRegisterService {
	@Autowired
	@Qualifier("usedDao")
	private ContactDao contactDao;

실행 결과

 

생성자 또는 멤버의 이름이 빈의 id와 같은 경우

· 빈의 id와 동일한 이름을 사용한 @Autowired 및 @Resource가 적용된 사용자 또는 멤버가 있다면 <qualifier>와 @Qualifier를 이용하지 않아도 의존 객체가 자동으로 주입된다.

■ appCtx.xml

<bean id="contactDao" 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" />

■ ContactRegisterService와 ContactSearchService 클래

@Autowired
//@Qualifier("usedDao")
private ContactDao contactDao;

 

실행 결과

매개변수 개수가 2개 이상인 경우

· 매개변수 개수가 2개 이상일 때도 의존 객체 자동 주입은 가능하다.

· 주입 대상 매개변수에 @Qualifier를 적용하면 된다.   

■ appCtx.xml

<bean id="firstBean1" class="ch05_pjt_01.contact.service.FirstBean">
		<qualifier value="usedBean" />
</bean>
<bean id="firstBean2" class="ch05_pjt_01.contact.service.FirstBean"/>
<bean id="firstBean3" class="ch05_pjt_01.contact.service.FirstBean"/>

<bean id="secondBean" class="ch05_pjt_01.contact.service.SecondBean"/>

<bean id="thirdBean" class="ch05_pjt_01.contact.service.ThirdBean"/>

<bean id="fourthBean1" class="ch05_pjt_01.contact.service.FourthBean">
    <qualifier value="usedBean" />
</bean>
<bean id="fourthBean2" class="ch05_pjt_01.contact.service.FourthBean"/>
<bean id="fourthBean3" class="ch05_pjt_01.contact.service.FourthBean"/>

<bean id="autoWiredEx" class="ch05_pjt_01.contact.service.AutoWiredEx"/>

 

■ AutoWiredEx.java

package ch05_pjt_01.contact.service;

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

public class AutoWiredEx {

    @Autowired
    public AutoWiredEx(@Qualifier("usedBean") FirstBean fBean, SecondBean sBean) {
        System.out.println("fBean: " + fBean);
        System.out.println("sBean: " + sBean);
    }
    
    @Autowired
    public void autowiredMethod(ThirdBean tBean, @Qualifier("usedBean") FourthBean fBean) {
        System.out.println("tBean: " + tBean);
        System.out.println("fBean: " + fBean);
    }
    
}

각각의 FirstBean, SecondBean, ThirdBean, FourthBean 클래스를 생성해준다.

구조도 실행결과
실행 결과

 

의존 객체 자동 주입 시 필수 여부 확인하기

· 빈을 생성하지 않고 @Autowired를 사용하면 의존 객체 자동 주입하는 과정에서 의존 객체를 찾을 수없어 에러가 뜬다.

· 에러가 발생하지 않게 하기 위해서는 required 속성을 이용한다.

· @Autowired에 required 속성을 false로 지정하면 의존 객체 자동 주입이 필수가 아닌 필요에 따라서 주입된다.

· 이러한 경우는 드물다.

@Autowired(required = false)
private ContactDao contactDao;
💡 required = false
주입 대상객체가 없어도 에러를 발생시키지 않는다는 의미
즉, 의존 주입 대상 객체가 설정되어 있다면 required=false라고 해도 자동으로 의존 객체가 주입된다.

 

@Inject를 이용한 의존 객체 자동 주입

@Autowired와 동일하게 @Inject 애너테이션을 이용해서 의존 객체를 자동으로 주입할 수 있다.

@Autowired @Inject
· required 속성을 이용해서 의존 객체가 없어도 에러를 피할 수있다. 
· 스프링에서 제공하는 애너테이션
· required 속성을 지원하지 않는다.
· 자바에서 제공하는 애너테이션으로 pom.xml 설정이 필요

 

메인 리포지터리에 접속하여 javax.inject 모듈을 검색한 후 메이븐(maven) 코드를 복사해 pom.xml에 붙여넣는다.

maven 코드 복사

■ pom.xml

<!-- spring-context 모듈 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

</dependencies>

이제 @Inject를 이용하여 의존 객체를 자동으로 주입해본다.

■ ContactRegisterService 클래스

//필드 자동 주입
@Inject
private ContactDao contactDao;

// 생성자 자동 주입
@Inject
public ContactRegisterService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

ContactSearchService 클래스

@Inject
private ContactDao contactDao;

@Inject
public ContactSearchService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

 

자동 주입 대상 객체가 2개 이상인 경우

@Autowired @Inject
@Qualifier 애너테이션 사용 @Named 애너테이션 사용

■ appCtx.xml

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

■ ContactRegisterService 클래스

//필드 자동 주입
@Inject
@Named("contactDao1")
private ContactDao contactDao;

// 생성자 자동 주입
@Inject
@Named("contactDao1")
public ContactRegisterService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

// 메서드 자동 주입
@Inject
@Named("contactDao1")
public void setWordDao(ContactDao contactDao) {
    this.contactDao = contactDao;
}

 ContactSearchService 클래스

@Inject
@Named("contactDao1")
private ContactDao contactDao;

@Inject
@Named("contactDao1")
public ContactSearchService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

@Inject
@Named("contactDao1")
public void setContactDao(ContactDao contactDao) {
    this.contactDao = contactDao;
}

 

디폴트 생성자가 없어서 에러가 발생하는 경우

· @Autowired를 적용할 때 필드 또는 메서드에 반드시 디폴트 생성자가 필요한 것과 같이 @Inject도 동일하다!·

· 디폴트 생성자가 있어야 정상적으로 빈이 생성되고 의존 객체를 자동 주입될 수 있다.

 

■ ContactRegisterService 클래스

//필드 자동 주입
@Inject
@Named("contactDao1")
private ContactDao contactDao;

// 생성자 자동 주입
//	@Inject
//	@Named("contactDao1")
public ContactRegisterService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

 ContactSearchService 클래스

@Inject
@Named("contactDao1")
private ContactDao contactDao;

//	@Inject
//	@Named("contactDao1")
public ContactSearchService(ContactDao contactDao) {
    this.contactDao = contactDao;
}

빈 생성 오류 발생