(1) 2장_스프링 코어(DI,AOP) - Bean설정과 의존성 주입

2021. 3. 15. 23:22개발공부/스프링 철저 입문

 


스프링 프레임워크 기초에서 가장 중요한 부분은 DI(Dependency Injection:의존성 주입)이라고 생각합니다. 객체를 다른 클래스에서 인스턴스로 일일이 초기화할 필요없이 컨테이너에 담아놓은 Bean을 꺼내 쓸 수 있기 때문이죠.

 

DI는 DI 컨테이너에 인스턴스를 등록해 사용 시 제공하는 특성 때문에 IoC(InversionofControl:제어의 역전) 디자인 패턴의 한 종류입니다. 그리고 DI 컨테이너에 등록하는 Component를 Bean이라고 하며 이를 찾아오는 행위를 lookup이라고 합니다.


Bean설정 방법


세 가지 방식이 있는데, 보통 Annotation 설정 방식과 다른 하나를 조합해서 쓴다고 합니다.

- Java 기반 설정방식 : 클래스에 @Configuration, 메서드에 @Bean을 붙여줍니다. 프로그램에서 자동으로 인식해 컨테이너에 등록합니다. 최근에 많이 활용하는 방식으로 스프링부트에서 쓰입니다.

- XML파일 설정방식 : 을 사용하는 방법으로 <bean> 요소에 클래스 네임을 기술하면 됩니다. <constructor-args>(생성자 주입)나 <property>(설정자 주입)요소를 사용합니다.

- Annotation 설정방식 :  앞선 두 방식과 달리 외부 파일을 생성하지 않아도 됩니다. @Component 같은 Marker Annotation이 부여된 클래스를 탐색해서 자동으로 등록합니다. 이런 탐색방식을 Component Scan이라고 합니다.


DI(의존성 주입) 방법


- 설정자 주입방식(setter injection) : setter를 생성해서 메서드나 생성자에 @Autowired이나 @Bean을 붙여 의존성을 주입합니다. 

- 생성자 주입방식(constructor injection) : 필드 주입방식보다 생성자 주입방식을 써야한다는 의견이 있습니다. 생성자 주입을 사용하면 의존성 주입할 필드를 final로 선언해 생성 후 변경되지 않도록 만들 수 있기 때문입니다. 이는 오직 생성자 주입방식에서만 가능합니다. 

1
2
3
4
5
6
    //컨스트럭터 인젝션을 애너테이션 기반 설정으로 표현한 예
    @ConstructorProperties({"userRepository""passwordEncoder"})
    public UserServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        //...
 
    }
cs

 

- 필드 주입방식(field injection) : 참고로 제가 스프링부트에서 모든 의존성을 주입한 방식은 필드 주입방식입니다. 이유는 편해서입니다. 생성자 선언도 필요없이 주입하고자 하는 필드에 @Autowired만 달아주면 되기 때문입니다. 코드가 간결해 보이는 장점이 있지만 책에선 생성자나 메서드를 생략하려면 반드시 DI 컨테이너를 사용해야 한다고 합니다. 관리 컨테이너가 없이 사용하면 무작위로 관리가 어렵기 때문일거라는 추측이 듭니다. * baeldung 블로그에서 reflection을 사용하기 때문에 cost가 더 드는 단점이 있다고 합니다. (reflection은 Runtime에 메서드, 클래스, 인터페이스를 변경할 때 쓰는 API라고 합니다) 그리고 사용이 쉽기 때문에 무분별한 의존성 주입이 많아진다는 우려도 있다합니다.


출처: 스프링 철저 입문

참고자료: baeldung 블로그 - Inversion of Contorl and DI