Spring service 에서 다른 service 호출 @Autowired - Spring service eseo daleun service hochul @Autowired

[Spring] @Autowired의 다양한 사용 방법 - required, Primary, Qualifier

1. 의존객체 타입의 빈이 없는 경우

다음과 같이 BookService 클래스와 BookRepository 인터페이스가 있다.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

BookRepository bookRepository;

@Autowired

public BookService(BookRepository bookRepository) {

this.bookRepository = bookRepository;

}

}

//

public interface BookRepository {

}

cs

BookService 클래스에는 @Service 애노테이션을 붙여 빈으로 등록해주었고 BookRepository는 애노테이션을 붙이지 않은 일반 자바 클래스이다.

BookRepository는 BookService의 의존객체이며 @Autowired를 붙여 BookService의 생성자를 통해 주입받도록 하였다.

이대로 실행하면 에러가 난다.

BookService 빈을 생성하려면 BookRepository 빈이 필요한데 IoC 컨테이너에서 해당하는 타입의 빈을 찾을 수 없으니 BookRepository를 빈으로 등록하라는 뜻이다.

코드를 바꿔 이번엔 setter로 주입받도록 해보자.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

BookRepository bookRepository;

@Autowired

public void setBookRepository(BookRepository bookRepository) {

this.bookRepository = bookRepository;

}

}

//

public interface BookRepository {

}

cs

실행하면 역시 에러가 발생한다.

생성자로 주입받던 것과 달리 Setter로 주입받도록 했기때문에 원래는 BookService의 인스턴스는 생성할 수 있는게 맞지만 @Autowired 애노테이션에 의해 BookRepository를 주입받도록 설정한 BookService도 생성되지 않는 것이다.

이렇게 @Autowired 애노테이션을 처리하던 중 해당하는 빈의 타입을 못찾거나 의존성 주입을 할 수 없는 경우에는 에러가 발생하며 어플리케이션 구동이 제대로 되지 않는다.

@Autowired에 required 속성값을 추가해보자.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

BookRepository bookRepository;

@Autowired(required = false)

public void setBookRepository(BookRepository bookRepository) {

this.bookRepository = bookRepository;

}

}

//

public interface BookRepository {

}

cs

이번엔 에러 없이 정상적으로 실행된다.

@Autowired(required = false)은 의존성을 'Optional'로 설정하는 것이다.

주입받을 의존객체가 필수적이지 않을 경우 @Autowired(required = false)로 설정해서 의존객체를 주입받지 못하더라도 빈을 생성하도록 할 수 있다.

결과적으로 BookService는 BookRepository를 주입받지 않은 상태로 IoC 컨테이너에 등록된다.

required 속성의 기본값은 true이기 때문에 지정하지 않을 경우 setter로 주입받게 했더라도 의존객체를 주입받지 못하면 항상 에러가 발생한다.

required = false는 @Autowired를 필드나 setter에 붙였을 경우에만 사용할 수 있다.

2. 의존객체 타입의 빈이 여러개인 경우

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

@Autowired

BookRepository bookRepository;

}

//

public interface BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class MyBookRepository implements BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class AnotherBookRepository implements BookRepository {

}

cs

BookService에서 BookRepository를 필드로 주입받도록 변경한다.

MyBookRepository, AnotherBookRepository 클래스를 새로 만들고 BookRepository를 구현하도록 한다.

둘 다 @Repository를 붙여 빈으로 등록함으로써 BookRepository 타입의 빈이 두개가 되었다.

이 경우 spring은 BookService에 어떤 BookRepository 빈을 주입해줄까?

결과는 주입해 줄 수 없다.

두 BookRepository중 어떤 빈을 원하는지 spring 입장에서 알 수가 없기 때문이다.

1) @Primary

@Primary 애노테이션을 사용해서 해당하는 타입의 빈이 여러개일 경우 우선적으로 주입할 빈을 지정할 수 있다.

MyBookRepository에 @Primary 애노테이션을 붙이자.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

@Autowired

BookRepository bookRepository;

}

//

public interface BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository @Primary

public class MyBookRepository implements BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class AnotherBookRepository implements BookRepository {

}

cs

이렇게 하면 spring은 BookService에 BookRepository를 주입할때 여러개의 빈이 존재할 경우 @Primary 애노테이션이 붙어있는 빈을 주입해준다.

2) Qualifier

@Qualifier 애노테이션을 사용해서 빈 id를 지정해서 주입받을 수 있다.

다음과 같이 주입받는 곳에 @Qualifier 애노테이션을 추가하자.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

@Autowired @Qualifier("myBookRepository")

BookRepository bookRepository;

}

//

public interface BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class MyBookRepository implements BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class AnotherBookRepository implements BookRepository {

}

cs

기본적으로 @Repository 애노테이션을 쓰면 빈 id는 소문자로 시작하는 클래스 이름과 동일하다.

따라서 MyBookRepository를 주입받도록 설정하려면 Qualifier 애노테이션에 myBookRepository라고 지정해주면 된다.

이렇게 @Primary와 @Qualifier 애노테이션은 같은 목적으로 쓸 수 있지만 @Primary가 더 type safe한 방법이다.

3) 해당하는 타입의 빈을 모두 주입받기

BookService에서 BookRepository를 주입받는 변수의 타입을 List로 변경한다.

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

import org.springframework.stereotype.Service;

import java.util.List;

@Service

public class BookService {

@Autowired

List<BookRepository> bookRepositories;

}

//

public interface BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class MyBookRepository implements BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class AnotherBookRepository implements BookRepository {

}

cs

이렇게 하면 spring은 BookRepository 타입의 빈을 모두 주입해준다.

4) 빈 id와 변수명을 동일하게

별로 spring에서 추천하는 방법은 아니지만 @Autowired는 타입을 보고 나서 여러 개일 경우 변수명과 빈 id도 확인하는 과정을 거친다.

예를 들어 지금처럼 BookRepository 타입의 빈이 MyBookRepository, AnotherBookRepository가 존재하는 상태에서 MyBookRepository를 주입받고 싶으면 주입받을 변수명을 myBookRepository로 하면 된다.

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

import org.springframework.stereotype.Service;

@Service

public class BookService {

@Autowired

BookRepository myBookRepository;

}

//

public interface BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class MyBookRepository implements BookRepository {

}

//

import org.springframework.stereotype.Repository;

@Repository

public class AnotherBookRepository implements BookRepository {

}

cs

여러 개의 빈 중에서 변수명과 빈 id가 동일한 빈이 주입된다.

References

인프런 - 백기선님의 스프링 프레임워크 핵심 기술

Toplist

최신 우편물

태그