Spring

의존 관계 자동 주입(@Autowired, @ComponentScan)

쭈녁 2024. 1. 2. 18:42

@ComponentScan

 

@ComponentScan 어노테이션은 @Component 가 붙은 모든 클래스 스프링 컨테이너에 Bean으로 등록한다.

이때 @ComponentScan 가 붙은 클래스가 존재하는 패키지를 포함한 하위의 파일들을 Scan의 대상으로 한다.

클래스 상단에 @Component 어노테이션을 사용하여 기존 수동으로 하던 Config 클래스를 통한 @Bean 등록을 @Component와 @ComponentScan을 통해 자동화할 수 있다.

 

Bean으로 컨테이너에 등록 되었다고 해서 의존관계에 있는 멤버 변수 (MemberService에서의 MemberRepository)가 주입이 된 것은 아니다. Spring은 이 또한 @Autowired 어노테이션을 통하여 의존관계 부여를 자동화하였다.

 

 

 

자동 Bean 등록, 자동 의존 관계 부여 예시)

 

@Component
public class MemberRepository{
	
}
@Component
public class MemberService{
    private final MemberRepository memberRepository;
    
    @Autowired
    public MemberService(MemberRepository memberRepository){
    	this.memberRepository = memberRepository;
    }
}
@Configuration
@ComponentScan
public class AutoConfig{
}

// -> AutoConfig의 설정 정보를 받아 사용

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoConfig.class);

 

 

위와 같이 구성하였을 때 @Component가 붙은 클래스의 정보를 모두 가져와 Bean에 등록하고

@Autowired 어노테이션을 바라보고 필요한 파라미터를 Bean 컨테이너에서 찾아 자동 의존 관계 부여해 준다.

자동 의존 관계 부여 시 조심해야 할 점은 타입과 Bean이 이름까지 같으면 BeanDefinitionException이 발생한다. 해당 부분은 다른 포스팅을 통하여 추가 정리 예정

 

@Autowired의 특징 : 생성자가 하나밖에 없다면 생략이 가능하다.

 

위 구성에서 더욱 간소화된 방법은 AutoConfig라는 클래스를 생략이 가능하다.

그 이유는 실행을 담당하는 Application 클래스의 @SpringBootApplication 어노테이션이 @ComponentScan이 포함하고 있기 때문이다.

이는 실행단이 포함되어 있는 패키지를 포함한 하위의 파일 중 @Component가 붙은 클래스를 모두 자동으로 Bean등록한다는 것이다.

 

 

@Component가 붙는 어노테이션

 

@Controller : MVC 컨트롤러로 인식

 

@RestController : @RequestBody + @Controller 컨트롤러 어노테이션을 포함하기 때문에 Component 대상

 

@Repository : 싱글톤으로 유지되며 데이터 접근 계층으로 인식함, 데이터 계층의 예외를 스프링의 추상화된 예외로 변환해 줌 때문에 여러 다른 DB로의 대응이 가능해진다.

 

@Configuration : 스프링 설정 정보로 인식, 생성자를 통해 주입되는 스프링 빈이 싱글톤을 유지하도록 추가 작업.

 

@Service : 추가적인 기능은 없으나 핵심 비즈니스가 이곳에 포함되며 개발자가 비즈니스 계층을 인식함.

 

 

 

자동 의존 관계 주입(@Autowired)의 방법

  • 생성자 주입
  • setter 주입
  • 필드 주입
  • 일반 메서드 주입

보편적으로 생성자를 통한 의존관계 주입을 사용하지만 각 방법 별 차이점을 정리해 보았다.

 

1. 생성자 주입

  • 객체가 생성될 때 단 한 번만 호출됨으로 의존 관계를 상수(final)로 고정시킬 수 있다.
  • 초기화 값을 안 받는 등의 생성자를 막아두고 반드시 받아 객체가 생성되게 함으로써 의존관계의 설정을 필수로 강제할 수 있다.
  •  불변(final)과 필수라는 특징이 있어 안정적인 의존관계를 부여하는 방법(때문에 보편적) 
@Component
public class OrderService{
     private final MemberRepository memberRepository;
     private final OrederRepository orderRepository;
     
     @Autowired
     public OrderService(MemberRepository memberRepository, OrederRepository orderRepository) {
         this.memberRepository = memberRepository;
         this.orderRepository = orderRepository;
     }
}
`

 

2. Setter 주입

  • 의존관계 선택과 변경에 열려있는 의존 관계 주입 방법 
  • 특정 상황에 의존 관계의 주입이 변경되거나 의존관계가 어떠한 결정에 의해 부여될 때는 사용할 수도 있다.
  • Setter를 열어 놓았다는 건 다른 클래스에서 접근하고 해당 의존관계를 final로 불변으로 만들 수 없음을 의미
  • 외부 접근, 지속적 변경이 가능하기 때문에 적절하게 조심히 사용해야 한다.
@Component
public class OrderService{
     private MemberRepository memberRepository;
     private OrederRepository orderRepository;
     
     @Autowired
     public void setMemberRepository(MemberRepository memberRepository) {
     	this.memberRepository = memberRepository;
     }
     @Autowired
     public void setorderRepository(OrederRepository orderRepository) {
     	this.orderRepository = orderRepository;
     }
}

 

3. 필드 주입

  • Spring컨테이너가 Bean 타입을 찾아 멤버변수에 직접 부여하도록 맴버 변수에 직접 자동 주입 하는 방법
  • 코드가 간결해지는 장점이 있지만 DI 컨테이너가 없이는 작동할 수가 없다(Spring 내부에서만 작동이 가능함)
  • 예를 들어 순수 자바코드의 테스트를 진행할 때 해당 코드는 의존관계 부여가 불가능하다(상수의 값을 지정하지 않아 컴파일 에러가 남)

 

@Component
public class OrderService{
     @Autowired
     private final MemberRepository memberRepository;
     @Autowired
     private final OrederRepository orderRepository;
}

 

4. 일반 메서드 주입

  • Setter 주입과 같은 개념, 하지만 여러 파라미터를 통해 한번에 여러 의존관계를 부여할 수 있다.
  • 같은 장, 단점을 공유한다. 변경이 필요할 때 조심히 적절하게 사용해야 한다.
@Component
public class OrderService{
     private MemberRepository memberRepository;
     private OrederRepository orderRepository;
     
     @Autowired
     public void init(MemberRepository memberRepository , OrederRepository orderRepository) {
     	this.memberRepository = memberRepository;
     	this.orderRepository = orderRepository;
     }
}