@Autowired를 사용하는 다양한 방법들

probsno·2021년 3월 31일
3

SpringCore

목록 보기
2/9

@Autowired 로 Bean 주입 받기

bean 을 주입하는 방법은 크게 3가지가 있다.

1. 필드

@Service
public class BookService {
    
    //필드 주입
    @Autowired(required = false) 
    BookRepository bookRepository;
    
}

필드에 @Autowired 어노테이션만 붙여주면 마법처럼 해당 타입의 bean을 주입 받을 수 있다.

  • 필드 인젝션의 특징
    • 간단함 (장점)
    • @Autowired(required=false) 옵션을 주면 해당 bean은 없으면 주입받지 않을 수도 있다 = optional 기본값은 true (장점)
    • final을 붙일 수가 없기 때문에 외부에서 변경이 가능함 (단점)
    • 순환 참조의 문제가 생길 수도 있음 ex. a->b를 주입받고 b->a를 다시 서로를 주입받아 참조하는 문제

2. setter

@Service
public class BookService {

    //의존성을 주입하려고 하기 때문에 bean이 없으면 에러가 발생함
    //required = false로 넣으면 bean이 없지만 오류가 나지 않고 지나감(옵셔널임)
    //required의 기본값은 true임
    @Autowired(required = false)
    public void setBookRepository(BookRepository bookRepository){
        this.bookRepository = bookRepository;
    }

}
  • setter 인젝션의 특징 (필드 주입과 사실은 동일함,,,)
    • 간단함 (장점)
    • @Autowired(required=false) 옵션을 주면 해당 bean은 없으면 주입받지 않을 수도 있다 = optional 기본값은 true (장점)
    • final을 붙일 수가 없기 때문에 외부에서 변경이 가능함 (단점)
    • 순환 참조의 문제가 생길 수도 있음 ex. a->b를 주입받고 b->a를 다시 서로를 주입받아 참조하는 문제

3. 생성자

@Service
public class BookService {

    //생성자로 bean을 주입할 경우 반드시 있어야 됨 옵셔날 X
    @Autowired
    public BookService(BookRepository bookRepository){
        this.bookRepository = bookRepository;
    }
}
  • 생성자 주입의 특징
    • final을 붙일 수 있기 때문에 외부에서 해당 빈을 함부로 변경할 수 없음 (장점)
    • 순환참조 문제를 미연에 방지할 수 있음 (장점)
    • @Autowired(required=false) 등으로 옵셔날하게 bean을 주입할 수 없다 (단점)

순환참조란?

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();
    }
}

순환참조를 방지할 수 있는 이유는?
코드에서 보다싶이 서로를 주입받아서 참조하기 때문에 무한히 프로그램이 돌게 된다.
하지만, 생성자 주입을 할경우 이 문제를 해결할 수 있는데...
바로, 빈을 주입하는 순서가 다르기 때문에.
필드 주입일 경우에는 모든 빈을 생성한 경우 주입을 하기 때문에 사전에 찾기 어려움.
그렇지만, 생성자 주입의 경우 빈을 하나하나 만들면서 생성자에 빈을 주입하기 때문에 프로그램 구동시 빈을 주입하면서 이미 순환참조의 문제에 빠지기 때문에 구동 되기 전에 알 수 가 있다!!

2개 이상의 빈을 주입 받는 방법

보통의 경우에는 빈이 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가지가 있다.

1. @Qualifier("빈이름")

@Service
public class BookService{
    
    //@Qaulifier("mybookRepository")에 해당 빈의 이름을 넣어주면 그 이름을 가지 빈을 찾아서 넣어줌
    @Autowired 
    @Qaulifier("mybookRepository")
    BookRipository bookRepository;

}

typo-safe하지 않기 때문에 기선이형은 추천하지 않는댓음

2. @Primary

//@Primary를 붙여준 bean이 우선순위가 되어 두개 이상의 동일한 타입의 빈이 있을 경우 얘가 들어가게 됨
@Repository
@Primary
public class YourbookRepository implements BookRepository {

}

typo-safe하기 때문에 추천하는 방법임

3. 이름으로 주입받기

@Service
public class BookService{
    
    //mybookRepository라는 이름을 가진 빈을 넣어줌
    @Autowired 
    BookRipository mybookRepository;

}

기선이형이 매우 추천하지 않음, 왜냐하면 직관적이지 않기 때문에

4. 리스트로 해당 타입의 빈 모두 받기

리스트로 해당 타입의 빈을 모두 받을 수 도있음

@Service
public class BookService{
    //여러개의 빈을 다 받을 경우
    @Autowired
    List<BookRepository> bookRepositoryList;
}

이렇게 하면 리스트로 해당 타입의 빈을 모두 가져오게 된다.

@Autowired의 원리

동작 원리

  • BeanPostProcessor
    • 새로 만든 빈 인스턴스를 수정할 수 있는 라이프 사이클 인터페이스
  • AutowiredAnnotationBeanPostProcessor extends BeanPostProcessor
    • 스프링이 제공하는 @Autowired와 @Value 애노테이션 그리고 JSR-330의
      @Inject 애노테이션을 지원하는 애노테이션 처리기.
profile
3개국어 쌉가능한 주니어 개발자

1개의 댓글

comment-user-thumbnail
2021년 11월 18일

잘 읽었습니다! :)
그런데 생성자주입의 단점을 "@Autowired(required=false) 등으로 옵셔날하게 bean을 주입할 수 없다 (단점)"라고 하기에는, @Nullalbe이라는 대안이 있는 걸로 알고 있습니다. 생성자주입은 코드가 외관상 덜 깔끔하다는 것 외에는 거의 단점이 없는 것 같습니다.

답글 달기