bean 을 주입하는 방법은 크게 3가지가 있다.
@Service
public class BookService {
//필드 주입
@Autowired(required = false)
BookRepository bookRepository;
}
필드에 @Autowired 어노테이션만 붙여주면 마법처럼 해당 타입의 bean을 주입 받을 수 있다.
@Service
public class BookService {
//의존성을 주입하려고 하기 때문에 bean이 없으면 에러가 발생함
//required = false로 넣으면 bean이 없지만 오류가 나지 않고 지나감(옵셔널임)
//required의 기본값은 true임
@Autowired(required = false)
public void setBookRepository(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
}
@Service
public class BookService {
//생성자로 bean을 주입할 경우 반드시 있어야 됨 옵셔날 X
@Autowired
public BookService(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
}
public class MyClass{
@Autowired
YourClass yourClass;
public void myMethod(){
yourClass.yourMethod();
}
}
public class YourClass{
@Autowired
MyClass myClass;
public void yourMethod(){
myClass.myMethod();
}
}
public class doCircle(){
@Autowired
MyClass myClass;
@Autowired
YourClass yourClass;
public circle(){
myClass.myMethod();
yourClass.yourMethod();
}
}
순환참조를 방지할 수 있는 이유는?
코드에서 보다싶이 서로를 주입받아서 참조하기 때문에 무한히 프로그램이 돌게 된다.
하지만, 생성자 주입을 할경우 이 문제를 해결할 수 있는데...
바로, 빈을 주입하는 순서가 다르기 때문에.
필드 주입일 경우에는 모든 빈을 생성한 경우 주입을 하기 때문에 사전에 찾기 어려움.
그렇지만, 생성자 주입의 경우 빈을 하나하나 만들면서 생성자에 빈을 주입하기 때문에 프로그램 구동시 빈을 주입하면서 이미 순환참조의 문제에 빠지기 때문에 구동 되기 전에 알 수 가 있다!!
보통의 경우에는 빈이 1개만 생성되어 별 문제 없지만,,,
bean의 타입이 인터페이스인경우 구현체가 여러개이고, 여러개의 구현체를 빈으로 등록한다면 2개 이상의 같은타입의 빈이 생길 수 가 있음. 이럴 경우 BeanFoctory는 어느 빈을 주입해야 되는지 모르기 때문에 에러를 발생시킴
예를들어 이런상황!
package com.example.demo;
public interface BookRepository {
}
@Repository
public class MybookRepository implements BookRepository{
}
@Repository
public class YourbookRepository implements BookRepository {
}
@Service
public class BookService{
//이럴경우 어떤 빈을 넣어줘야할지 몰라서 에러가 발생함
@Autowired
BookRipository bookRepository;
}
해결방법을 총 4가지가 있다.
@Service
public class BookService{
//@Qaulifier("mybookRepository")에 해당 빈의 이름을 넣어주면 그 이름을 가지 빈을 찾아서 넣어줌
@Autowired
@Qaulifier("mybookRepository")
BookRipository bookRepository;
}
typo-safe하지 않기 때문에 기선이형은 추천하지 않는댓음
//@Primary를 붙여준 bean이 우선순위가 되어 두개 이상의 동일한 타입의 빈이 있을 경우 얘가 들어가게 됨
@Repository
@Primary
public class YourbookRepository implements BookRepository {
}
typo-safe하기 때문에 추천하는 방법임
@Service
public class BookService{
//mybookRepository라는 이름을 가진 빈을 넣어줌
@Autowired
BookRipository mybookRepository;
}
기선이형이 매우 추천하지 않음, 왜냐하면 직관적이지 않기 때문에
리스트로 해당 타입의 빈을 모두 받을 수 도있음
@Service
public class BookService{
//여러개의 빈을 다 받을 경우
@Autowired
List<BookRepository> bookRepositoryList;
}
이렇게 하면 리스트로 해당 타입의 빈을 모두 가져오게 된다.
동작 원리
잘 읽었습니다! :)
그런데 생성자주입의 단점을 "@Autowired(required=false) 등으로 옵셔날하게 bean을 주입할 수 없다 (단점)"라고 하기에는, @Nullalbe이라는 대안이 있는 걸로 알고 있습니다. 생성자주입은 코드가 외관상 덜 깔끔하다는 것 외에는 거의 단점이 없는 것 같습니다.