Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

Develog

코드스테이츠 37일차 본문

코드스테이츠

코드스테이츠 37일차

안형준 2022. 6. 17. 18:30

학습 내용

  • 스프링에서 DI 할 수 있는 다양한 의존관계 주입 방법에 대해 학습합니다.
  • 생성자 주입 방법(Constructor-based DI)를 권장하는 이유를 학습합니다.
  • 의존 관계 주입 방법 중 수정자 주입(Setter-based DI)와 필드 주입(Field-based DI)의 단점들에 대해 학습합니다.

 

Spring DI(Dependency Injection)

4가지 의존관계 주입 방법이 있다.

  • 생성자 주입
  • 수정자 주입 (setter 주입)
  • 필드 주입
  • 일반 메서드 주입

 

생성자 주입

생성자를 통해서 의존 관계를 주입 받는 방법이다.

생성자에 @Autowired를 하면 스프링 컨테이너에 @Component로 등록된 빈에서 생성자에 필요한 빈들을 주입한다.

여기서 잠깐! @Component는 무엇일까?

@Component는  개발자가 직접 작성한 Class를 Bean으로 등록하기 위한 Annotation이다.

Component 애너테이션은 Bean으로 생성해서 주입될 대상 클래스에 달아주는 것이다.

 

특징

  • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장된다.
  • 불변과 필수 의존 관계에 사용된다. (의존 관계의 불변성은 한 번 정해지면, 변화하지 않는다는 의미이다. 즉 생성자 호출 시점에서만 의존 관계가 주입되기 때문에 의존 관계에 변화가 발생하지 않는다.)
  • 생성자가 1개만 존재하는 경우에는 @Autowired를 생략해도 자동 주입 된다.
  • NullPointerException을 방지할 수 있다. (NullPointerException은 실제 값이 아닌 null을 가지고 있는 객체/변수를 호출할 때 발생하는 예외이다.)
  • 주입받을 필드를 final로 선언 가능하다.

 

생성자는 1개일 때 @Autowired가 없어도 작동이 되는 이유는?

  • 스프링이 해당 클래스 객체를 생성하여 빈에 넣어야하는데 생성할 때 생성자를 부를 수 밖에 없게 된다.
  • 그렇기 때문에 빈을 등록하면서 의존 관계 주입도 같이 발생하게 된다.

수정자 주입 (setter 주입)

setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존 관계를 주입하는 방법

 

특징

  • 선택과 변경 가능성이 있는 의존 관계에 사용된다.
  • 자바빈 property 규약의 수정자 메서드 방식을 사용하는 방법이다.
  • 생성자 주입과 차이점은 생성자 대신 set필드명 메서드를 생성하여 의존 관계를 주입하게 된다.
  • 수정자의 경우 @Autowired를 입력하지 않으면 실행이 되지 않는다.

 

필드 주입

필드에 @Autowired 붙여서 바로 주입하는 방법입니다.

 

특징

  • 코드가 간결해서 예전에 많이 사용된 방식이지만, 외부에서 변경이 불가능하여 테스트하기 힘들다는 단점이 있다.
  • DI 프레임워크가 없으면 아무것도 할 수 없다.
  • 실제 코드와 상관 없는 특정 테스트를 하고 싶을 때 사용할 수 있다.
  • 하지만 정상적으로 작동되게 하려면 결국 setter가 필요하게 돼서 수정자 주입을 사용하는게 더 편리해진다.

 

일반 메서드 주입

일반 메서드를 사용해 주입하는 방법이다.

 

특징

  • 한번에 여러 필드를 주입 받을 수 있다.
  • 일반적으로 사용되지 않는다.

 

위 4가지 방법 중 보편적으로 생성자 주입 방법을  사용한다.

 

주입할 스프링 빈이 없을 때 동작해야하는 경우가 있다.

  • @Autowired만 사용하는 경우 required 옵션 기본값인 true가 사용되어 자동 주입 대상이 없으면 오류가 발생하는 경우가 있을 수 있다.
  • 스프링 빈을 옵셔널하게 해둔 상태에서 등록이 되지 않고, 기본 로직으로 동작하게 하는 경우
  • 자동 주입 대상 옵션 처리 방법

 

생성자 주입을 사용해야하는 이유

과거에는 수정자, 필드 주입을 많이 사용했지만, 최근에는 대부분 생성자 주입 사용을 권장한다.

 

그 이유는?

 

불변

  • 의존 관계 주입은 처음 애플리케이션이 실행될 때 대부분 정해지고 종료 전까지 변경되지 않고 변경 되어서는 안된다.
  • 수정자 주입 같은 경우에는 이름 메서드를 public으로 열어두어 변경이 가능하기 때문에 적합하지 않다.
  • (누군가 실수로 변경할 수도 있고, 애초에 변경하면 안되는 메서드가 변경할 수 있게 설계하는 것은 좋은 방법이 아니다.
  • 생성자 주입은 객체를 생성할 때 최초로 1번만 호출되고 그 이후에는 다시는 호출되는 일이 없기 때문에 불변하게 설계할 수 있다.

누락

  • 호출 했을 때는 NPE(Null Point Exception)이 발생하는데 의존관계 주입이 누락 되었기 때문에 발생한다.
  • 생성자 주입을 사용하면 주입 데이터 누락 시 컴파일 오류가 발생한다.

final 키워드 사용 가능

  • 생성자 주입을 사용하면 필드에 final 키워드를 사용할 수 있다.
  • 생성자에서 값이 설정되지 않으면 컴파일 시점에서 오류를 확인할 수 있다. (java: variable (데이터 이름) might not have been initialized)
  • 생성자 주입을 제외한 나머지 주입 방식은 생성자 이후에 호출되는 형태이므로 final 키워드를 사용할 수 없다.

순환 참조

  • 순환 참조를 방지할 수 있다.
  • 개발하다보면 여러 컴포넌트 간에 의존성이 생기게 됩니다. (A → B를 참조하고, B → A를 참조)
  • 필드 주입과 수정자 주입은 빈이 생성된 후에 참조를 하기 때문에 애플리케이션이 어떠한 오류와 경고 없이 구동된다.
  • 생성자를 통해 주입하게되면 BeanCurrentlyInCreationException이 발생하게 된다.

 

생성자 주입 방식의 장점을 요약하자면?

  • 의존관계 설정이 되지 않으면 객체생성이 불가능하다.
  • 의존성 주입이 필요한 필드를 final 로 선언 가능하다.
  • (스프링에서) 순환참조 감지가 가능하다.
  • 테스트 코드 작성에 용이하다.
  • 수정자 주입이 필요한 경우가 있을 수 있지만 옵션이 필요할 때만 선택하면 된다.

 

Component Scan (스캔)

스프링은 설정 정보 없이 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.

지금까지는 스프링 빈을 등록할 때 자바 코드의 @Bean or XML의 등의 설정 정보에 등록할 스프링 빈들을 직접 작성했다.

하지만 이렇게 수작업으로 등록하게 되면 설정 정보가 커지고, 누락하는 등 다양한 문제가 발생할 수 있다.

그 해결 방법으로 @ComponentScan을 사용한다.

@ComponentScan은 @Component가 붙은 모든 클래스를 스프링 빈으로 등록해주기 때문에 설정 정보에 붙여주면 된다.

의존관계도 자동으로 주입하는 @Autowired 기능도 제공한다.

 

Component Scan (스캔)의 주의사항

컴포넌트 스캔을 사용하면 @Configuration이 붙은 설정 정보도 자동으로 등록된다.

@Configuration이 붙은 설정 정보가 자동 등록되는 이유는 @Configuration 코드에 @Component 애너테이션이 붙어있기 때문이다.

 

기존에 작성한 AppConfig이 있다면 정상적인 작동이 되지 않는다.

 

  • 새 프로젝트로 진행할 경우엔 문제가 되지 않는다.
  • AppConfig 등 @Configuration 설정이 된 파일이 있을 시 아래 코드 추가해주면 된다. : @ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class))

 

정리하자면

@Component - @Configuration이 등록된 곳에서 @Component를 가져오기 위해 사용된다.

@Autowired - 생성자 의존성 주입에 필요한 설정 정보 대신 의존관계 자동 주입을 해주게 된다.

 

basePackages

탐색할 패키지의 시작 위치를 지정하고, 해당 패키지부터 하위 패키지까지 모두 탐색한다.

  • @ComponentScan()의 매개변수로 basePackages = “”를 줄 수 있다.
  • 지정하지 않으면, @ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
  • 스프링 부트를 사용하면 @SpringBootApplication 를 이 프로젝트 시작 루트 위치에 두는 것이 추천된다.

 

컴포넌트 스캔 기본 대상

  • @Component : 컴포넌트 스캔에서 사용된다.
  • @Controller & @RestController : 스프링 MVC 및 REST 전용 컨트롤러에서 사용된다.
  • @Service : 스프링 비즈니스 로직에서 사용된다.
  • @Repository : 스프링 데이터 접근 계층에서 사용된다.
  • @Configuration : 스프링 설정 정보에서 사용된다.

 

Service, Controller, Repository 클래스의 소스 코드에는 @Component를 포함하고 있다.

 

컴포넌트 스캔 총정리

컴포넌트 스캔을 이용해서 스프링 빈을 등록해보고 @Autowired를 사용

  • 장점
  • @Componenet 애너테이션이 붙은 클래스를 찾아서 스프링 빈으로 등록해주는 방식이다.
  • @Configuration
  • @Autowired

 

필터

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
  • excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.
  • FilterType 옵션

'코드스테이츠' 카테고리의 다른 글

코드스테이츠 39일차  (0) 2022.06.21
코드스테이츠 38일차  (0) 2022.06.20
코드스테이츠 36일차  (0) 2022.06.16
코드스테이츠 35일차  (0) 2022.06.15
학습 계획표  (2) 2022.06.15