[36일차] DI(의존 주입 방법, Component)

유태형·2022년 6월 17일
0

코드스테이츠

목록 보기
36/77

오늘의 목표

  1. 의존 주입 방법
  2. Component
  3. BeanDefinition



내용

의존 주입 방법

의존관계 주입 방법은 4가지가 존재합니다.

  1. 생서자 주입
  2. 수정자(Setter) 주입
  3. 필드 주입
  4. 일반 메서드 주입


생성자 주입

생성자를 통해서 의존 관계를 주입 받는 방법입니다. @Component로 등록된 클래스에서 생성자에 @Autowired 애너테이션을 추가합니다.

  • 생성자 호출 시점에 딱 1번만 호출됩니다.
  • 생서자가 1개만 존재할 경우 @Autowried 생략 가능
  • NullPointerExeption 방지
  • 주입 받을 필드를 final로 선언 가능


수정자 주입

Setter 메서드의 매개변수로 의존 객체를 주입하는 방법입니다.

  • 실행중에 선택 가능하며 추후에 언제라도 변경가능한 의존관계에 사용됩니다.
  • set필드명(주입 객체)형식의 메서드로 의존관계를 주입합니다.
  • @Autowired를 필수적으로 입력하여야 의존주입이 됩니다.
@Autowired
public void set클래스명(클래스명 객체명){
	this.객체명 = 객체명;
}


필드 주입

필드에 @Autowired를 붙여서 바로 주입합니다.

  • 외부에서 변경이 불가능합니다.
  • 테스트를 진행하기 힘듭니다.(Setter 필요)


일반 메서드 주입

일반 메서드를 사용해 의존을 주입합니다.

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


의존 주입시 옵션 들

의존 주입시 주입 하려는 객체가 스프링 컨테이너에 존재하지 않는 다면 어떻게 될 까요?
기본설정으로는 에러가 발생하며 실행을 멈춥니다. 하지만 만약 의존 객체가 존재하지 않더라도, 계속 진행하고 싶거나 다른 값을 주입하고 싶을땐 옵션을 이용하여 처리합니다.

옵션설명
@Autowired(required=false)주입할 대상 객체가 존재하지 않으면 메서드를 호출하지 않습니다.
@Nullable주입할 대상 객체가 존재하지 않으면 Null이 입력됩니다.
Optional<>주입할 대상 객체가 존재하지 않으면 Optional.empy가 입력됩니다.


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

과거에는 수정자, 피드 주입을 많이 사용하였지만, 최근에는 대부분 생성자 주입을 많이 사용하고 권장하고 있습니다.

  • 불변 : 생성되고 종료될 때까지 누군가 고의든 아니든 변경하는 것은 좋은 방법이 아니므로 생성시 최초 1회만 호출되도록 합니다.
  • 누락 : 수정자, 필드와는 다르게 생성자에서는 NullPointerException발생시 에러를 발생시킵니다.
  • final : 생성자는 객체 생성시 최초 1회만 호출되므로 상수를 지정할 수 있습니다. 다른 메서드들에서는 final상수 변경이 불가능합니다.
  • 순환 참조 : 순환참조(참조했던 객체를 다시 참조)를 방지 할 수 있습니다. 생성자 주입에서는 참조간 순환이 발생할 시 BeanCurrentlyInCreationException에러를 발생시켜 미리 예방할 수 있습니다.



Component

@ComponentScan

@ComponentScan은 스프링 설정 정보 없이 자동으로 빈 객체를 등록하는 기능을 제공합니다.

지금까지는 @Configuration 애너테이션이 지정된 설정 정보 클래스에 @Bean애너테이션이 지정된 메서드를 호출하여 스프링 컨테이너에 빈 객체를 추가하였지만, 스프링의 사이즈가 커지면 누락되는 빈 객체가 발생할 수도 있으므로 자동으로 빈 객체를 등록하는 기능이 필요하게 되었습니다.

@Configuration
@ComponentScan
public class AutoAppConfig{

}

@ComponentScan 에너테이션을 사용하면 @Component 에너테이션이 붙은 클래스들을 스프링이 자동으로 스프링 컨테이너에 빈 객체로 추가하여 줍니다.
(@Configuration 애너테이션에 @Component에너티이션도 포함되어있으므로 설정 정보 클래스도 함께 스프링 컨테이너에 빈 객체로 추가됩니다.)

  • @Component : @Configuration 설정정보 클래스의 @ComponentScan 이 해당 에너테이션이 붙은 클래스를 스프링 컨테이너에 빈 객체로 추가합니다.
  • @Autowired : 의존성 주입에 필요한 설정 정보 대신 의존관계 자동 주입을 해주게 됩니다.


basePackages

@ComponentScan(basePackages="탐색을 시작할 패키지 위치")

@ComponentScan이 탐색을 시작할 패키지의 위치를 지정합니다. 해당 패키지 부터 모든 하위 패키지를 탐색합니다.
basePackages를 지정하지 않으면 @ComponentScan애너테이션이 위치한 패키지부터 모든 하위패키지를 탐색합니다.
스프링 부트를 사용하면 @SpringBootApplication 애너테이션을 프로젝터의 시작 루트 위치에 두는 것을 추천합니다.



스캔 대상

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

@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class))

  • includeFilters : 컴포넌트 스캔 대상을 추가로 지정합니다.
  • excludeFilters : 컴포넌트 스캔 대상에서 제외합니다.
@Filter(type = )설명
FilterType.ANNOTATION기본값이고, 애너테이션을 인식해서 동작합니다.
FilterType.ASSIGNABLE_TYPE지정한 타입과 자식 타입을 인식해서 동작합니다.
FilterType.ASPECTJAspectJ패턴을 사용합니다.
FilterType.REGEX정규 표현식을 나타냅니다.
FilterType.CUSTOM인터페이스를 구현해서 처리합니다.



BeanDefinition

AnnotationConfigApplicationContext객체에서 .getBeanDefinitionNames() 메서드를 호출하여 BeanDefinition 목록을 반환 받을 수 있습니다.

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();

컨테이너.getBeanDefinition(빈설정이름) 메서드를 사용하여 빈 설정을 가졍올수도 있습니다.

 BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

BeanDefinition의 정보에는 클래스명, 범위, 초기화 등 다양한 정보들이 있습니다.




후기

@Configuration과 @Bean, @ComponentScan 과 @Component, @Autowired는 스프링에서 중요한 IoC, DI를 구현하기 위해서 사용되는 아주 중요한 애너테이션 들입니다. 옵션 하나하나 세세하게 알 필요까진 아직 없을 테지만 어떻게 동작되고 어떤 순서로 진행되는지는 지금 완전히 익혀둬야 할 듯 합니다.




GitHub

https://github.com/ds02168/CodeStates_Spring/tree/main/section2-week3-DI2

profile
오늘도 내일도 화이팅!

0개의 댓글