1. 시작하게 된 계기 및 다짐 😮
  • 이번 코드스테이츠의 백엔드 엔지니어링 개발자 부트캠프에 참여하게 되면서 현직개발자 분들의 빠른 성장을 위한 조언 중 자신만의 블로그를 이용하여 배운 것 들을 정리하는게 많은 도움이 된다 하여 시작하게 되었다.

    • 그 날 배웠던 것을 길지 않아도 좋으니 정리하며 복습하는 습관 기르기
    • 주말에 다음주에 배울 내용들을 예습
    • 코딩 문제와 java코드들은 꾸준히 학습
    • 자료구조를 이용한 알고리즘 문제 해결 학습
  1. 학습 목표 😮
목표결과
Spring DI(Dependency Injection)의 의미를 이해O
생성자 주입 방법(Constructor-based DI)권장 이유 이해O
Component 스캔에 대해 이해O
  1. 정리

Spring DI(Dependency Injection)

1. Spring DI(Dependency Injection)
 1). 생성자 주입
 2). 수정자 주입(setter 주입)
 3). 필드 주입
 4). 일반 메서드 주입

1). 생성자 주입
 - @Autowired를 하면 스프링 컨테이너에 @Component로 등록된 빈에서 생성자에 필요한 빈들을 주입한다.
 - 특징
   (1) 생성자 호출 시점에 딱 1번만 호출되는 것이 보장
   (2) 불변과 필수 의존 관계에 사용 
   (3) 생성자가 1개만 존개하는 경우 @Autowired생략 가능
   (4) NullPointerException을 방지
   (5) 주입받을 필드를 final로 선언 가능

[예제 코드]
@Component
public class OrderServiceImpl implements OrderService {
   private final UserRepository userRepository;
   private final DiscountInfo discountInfo;

    @Autowired
    public [OrderServiceImpl](UserRepository userRepository, DiscountInfo discountInfo) {
       this.userRepository = userRepository;
       this.discountInfo = discountInfo;
    }
}


2). 수정자 주입(setter 주입)
 - setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통한 의존관계 주입
 - 특징 
   (1) 선택과 변경 가능성이 있는 의존 관계에 사용
   (2) 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법
 - 생성자 주입과 차이점은 생성자 대신 set필드명 메서드를 생성하여 의존 관계를 주입
 - 수정자의 경우 @Autowired를 입력하지 않으면 실행되지 않음
    (1) @Component가 실행하는 클래스를 스프링 빈으로 등록합니다.
    (2) 스프링 빈으로 등록한 다음 의존 관계를 주입하게 되는데 @Autowired 있는 것들을 자동으로 주입하게 됩니다.

[예제 Code]
@Component
public class OrderServiceImpl implements OrderService {
    private UserRepository userRepository;
    private DiscountInfo discountInfo;

    @Autowired
     public [void setUserRepository](UserRepository userRepository) {
	this.userRepository = userRepository;
     }

    @Autowired
     public [void setDiscountInfo](DiscountInfo discountInfo) {
	this.discountInfo = discountInfo;
     }
}

3). 필드 주입
 - 필드에 @Autowired를 붙여서 주입
 - 특징
   (1) 코드가 간결하지만, 외부에서 변경이 불가능하여 테스트가 어렵다
   (2) DI 프레임워크가 없으면 아무것도 할 수없음
   (3) 실제 코드와 상관없는 테스트에 사용됨
   (4) 정상적으로 작동하려면 setter 가 필요하게 되서 수정자 주입을 사용하는게 편함

[예제 Code]
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private DiscountInfo discountInfo;

}

4). 일반 메서드 주입
 - 한번에 여러 필드를 주입받을 수 있지만, 잘 사용하지 않음

5). 옵션처리
 - 주입할 스프링 빈이 없을 경우 동작이 필요할때
    @Autowired(required=false);
    [ex] public void setNoBean1(User noBean1);
 - 일반적으로 @Autowired만 사용하는 경우 requried 옵션 기본값인 true가 적용되어 자동 주입대상이 없으면 오류발생
 - 옵션 처리 방법
   (1) @Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출되지 않음
   (2) @Nullable : 자동 주입할 대상이 없으면 null이 입력
   (3) Optional<user> : 자동 주입할 대상이 없으면 Optional.empty가 입력됨

6). 생성자 주입을 사용해야 하는 이유
 (1) 불변
    - 의존 관계 주입은 실행시 정해지고나서 변경되지 않고 변경되서는 안되기 때문
    - 수정자 주입의 경우, 메서드를 public으로 열어두어 변경이 가능하므로 안됨
    - 객체 생성시 최초1 번만 호출되고 이후 호출되지 않게
 (2) 누락
    - 호출시 NPE(Null Point Exception)이 발생하는데, 의존 관계 주입이 누락되었기 떄문
    - 생성자 주입을 사용하면 주입 데이터 누락시 컴파일 오류가 발생
 (3) final 키워드 사용 가능
    - 생성자 주입을 사용하면 필드에 final 키워드 사용가능
    - 나머지 방식은 생성자 이후에 호출되므로 final 키워드를 사용할 수 없음
 (4) 순환참조
    [순환참조] : 메서드를 호출할 때 서로가 의존클래스 이기에 A->B가 필요하고 B->A가 필요하여 무한 루프에 빠지게 되는 상황
    - 순환 참조를 방지
    - 개발시 여러 컴포넌트 간에 의존성이 생기는데, 필드 주입과 수정자 주입은 빈이 생성된 후 참조하기에 오류와 경고 없이 구동되므로 실제 코드가 호출되기 전까지 문제를 알 수 없음 -> 순환 참조가 발생해도 실행됨
    - 생성자를 통해 주입하면 BeanCurrentlyInCreationException이 발생 
       [@Lazy 어노테이션을 통해서 임의로 해결도 가능]
 (5) 수정자 주입이 필요시, 필요에 의해서만 사용하믄됨






Component 스캔

1. Component Scan
 - 설정 정보 없이 자동으로 스프링 빈을 등록하는 컴포넌트 스캔 기능
 - @ComponentScan을 통해 @Component가 붙은 모든 클래스를 스프링 빈으로 등록해준다.
    - 의존관계도 자동으로 주입하는 @Autowired 기능도 함께 제공
 - @Bean으로 등록한 클래스를 볼 수 없음
 - @Configuration이 붙은 설정 정보도 자동으로 등록되고, 그외(@Target,Rententation,documented )
 - 기존에 작성한 AppConfig가 있다면 정상적으로 작동하지 못하는데, 이 경우
    [@ComponentScan(excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class))]
    코드를 작성해 해결 가능
    
 
[예제 Code]

@Configuration
@ComponentScan
public class AutoAppConfig {

}

[@Component - @Configuration이 등록된 곳에서 @Component를 가져오기 위해 사용됩니다.]
[@Autowired - 생성자 의존성 주입에 필요한 설정 정보 대신 의존관계 자동 주입을 해주게 됩니다.]


2. CompoenentScan() _basePackages
 - 탐색할 패키지의 시작위치를 지정하고, 해당 패키지의 하위 패키지를 모두 탐색
 - @ComponentScan()의 매개변수로 basePackages =""를 줄수있고, 지정하지 않을시 default로 클래스의 패키지가 시작위치
    - [설정정보 클래스의 위치를 프로젝트 최상단에 두고 패키지 위치를 지정하지 않는 방법이 가장 편하다]
 - 스프링 부트를 사용시, @SpringBootApplication를 프로젝트 시작위치에 두는게 좋음(@ComponentScan()이 들어있음)


3. ComponentScan의 대상
 - @Component : 스캔 대상
 - @Controller & RestController : 스프링 MVC 및 REST 전용 컨트롤러에서 사용됨
 - @Service : 스프링 비지니스 로직에서 사용됨
    - 특별한 처리가 없고, 개발자들이 핵심 비지니스 로직이 여기에 있다는 비지니스 계층인식에 도움이됨
 - @Repository : 스프링 데이터 접근 계층에서 사용됨
   - 스프링 데이터 접근 계층으로, 예외를 스프링 예외로 변환
 - @Configuration : 스프링 설정정보 사용하고, 스프링 빈이 싱글톤 유지하도록 추가처리

[extra]
필터
 - includeFilters : 컴포넌트 스캔 대상 추가 지정
 - excludeFilters : 컴포넌트 스캔에서 제외할 대상 지정

[옵션]
 - ANNOTATION: 기본값, 애너테이션으로 인식해서 동작합니다.
 - ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작합니다.
 - ASPECTJ: AspectJ 패턴을 사용합니다.
 - REGEX: 정규 표현식을 나타냅니다.
 - CUSTOM: TypeFilter라는 인터페이스를 구현해서 처리합니다.






  1. 피드백 😮
  • Spring에서 Configuration대신 ComponentScan을 이용하여 설정정보없이(@Bean을 통해 메서드) Bean등를 가져오는 방법을 알아보았다.

  • 이는 Compoenent,Controller등 여러 Scan대상이 있는데 각 애너테이션은 특정 상황에 따라 사용하는 애너테이션들이 달라진다.

  • 따로 필요한 Bean들을 등록해주지 않고 필요한 것에 Component를 붙여 좀더 편리하게 빈들을 등록하고 의존성을 따로 주입해줄 필요가 없어 필요하다.

  1. 앞으로 해야 될 것 😮
  • 매일 꾸준히 할 것
    • 꾸준히 velog 작성
    • Java 언어 및 Algorithm 공부(Coding-Test)
    • 틈틈히 운동 하기

  • 내일 해야 할 것
    • 관심 지향 프로그래밍(AOP)에 대한 학습
    • 오늘 배웠던 DI에 대한 전체적인 복습
profile
Will be great Backend-developer

0개의 댓글