Spring

Spring 올바른(?)빈주입?

yoon9 2023. 2. 6. 18:40

스프링을 이용하여 개발을 하면 무조건을 하는 의존성주입이 있다.

자바 객체를 스프링컨테이너가 빈으로 등록을 하면 이제 빈을 관리해주는 스프링컨테이너가

빈의 라이프사이클을 관리해준다. -> 알아서 싱글톤 패턴으로 관리가 되게 해준다.

사실상 스프링을 이용해서 개발을 하다보면 직접 new()를 하여서 개발하는경우는 빈등록이 되지 않은 경우 아닌 이상 없다고 생각한다...

이제 IOC과 DI의 개념이 들어오는데 항상 이 둘은 붙어있다...

IOC는 무엇일까? inversion of Controll 제어의 역전이다...

개발자가 개발을 하는데 제어는 스프링컨테이너가 해준다.

 

무슨말일까?

스프링을 이용하여 개발 중에 빈으로 등록된 컴포넌트(빈)들의 객체 생성 및 소멸 등 알아서 스프링컨테이너가 해주겠다 이것이다..장점이야 여러가지가 있겠지만 개발중에 느낀 장점은 객체 생성에 대해 개발자가 신경을 안써도 된다는 점에 좋은 것 같다. 객체지향 5원칙에 맞게 대부분 인터페이스에 컴포지션으로 의존성을 주는데 이것을 스프링이 알아서(?) 타입에 맞게 넣어준다.->느슨한 결합이 된다.

 

 

 

DI Denfendency Injection

“A가 B를 의존한다” 토비의 스프링에서는 “의존 대상 B가 변하면, 그것이 A에 영향을 미친다”고 한다. 즉, B의 기능이 추가되거나 변경되면 그 영향이 A에 미치는 것이다.

객체지향개발중에는 의존성이라는게 빠질 수 없다.

이러한 의존성 주입도 스프링이 해준다. 그니까 외부로부터 의존성이 주입이 되는 것이다.(개발자가 의존성을 new()해주지 않는다..)

좀 더 자세히 말을 하자면 인터페이스를 구현하고  클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임시에 스프링이 의존관계를 동적으로 주입을 해준다-> 유연하다, 결합도가 낮아진다.

이렇게 보면 IOC와 DI는 직접적으로 연관이 되어 있다. 

아무튼 이정도 까지 알고 본론으로 넘어가자

 

그래서 이렇게 예전의 내용을 간단하게 복습을 하였고..(?)

이번에도 자주 까먹어서 기록을 할려고 한다..

 

의존성 주입에는 3가지가 있다.

생성자 인젝, 세터 인젝, 필드 인젝

 

 

1. 생성자 인젝

 

@RequiredArgsConstructor
@Service
public class AuthService   {
    private final MemberRepository memberRepository;
    private final BCryptPasswordEncoder bCryptEncoder;
}

public class AuthService   {
    private MemberRepository memberRepository;
    private BCryptPasswordEncoder bCryptEncoder;
    
    @Autowired
    public AuthService(MemberRepository memberRepository,BCryptPasswordEncoder bCryptEncoder){
    this.memberRepository =memberRepository;
    this.bCryptEncoder=bCryptEncoder;
}

생성자를 이용하여서 주입을 받는 경우다. 생성자 주입을 가장 추천한다.

딱 생성자 호출할 때 한 번 실행되어서 의존성이 주입이 된다.

그리고 객체의 불변성을 보장받을 수 있다. 

 

 

2.세터 인젝

public class AuthService   {
    private MemberRepository memberRepository;
    private BCryptPasswordEncoder bCryptEncoder;
    
    @Autowired
    public setMemberRepository(MemberRepository memberRepository){
    this.memberRepository =memberRepository;
   }
   
    @Autowired
    public setBCryptEncoder(BCryptPasswordEncoder bCryptEncoder){
    this.bCryptEncoder =bCryptEncoder;
   }
}

세터 인젝이다.. 근데 개인적으로 개발 중에 한 번도 세터 인젝을 해본 적이 없다. 굳이 생성자를 안 사용하고 세터 인젝을 하는 이유가 그냥 게터세터 사용해서 만든건가..? 뭐 방법은 여러가지니까..

 

 

3.필드 인젝

public class AuthService   {
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private BCryptPasswordEncoder bCryptEncoder;
    
}

필드 인젝이다. 제일 간단하다. 필자도... 처음에 이방법을 많이 이용하였다.

하지만 좋지 않다고만 하여서 생성자주입으로 방식을 바꾸었다.

 

왜 안좋다고하는 것일까? 

필드 인젝을 하는경우에는 프레임워크에 반드시 종속이 되어서 좋지 않고 테스트 코드를 작성하기에도 좋지않다.

테스트 코드도 사실 빈을 띄워서 하는 경우가 대부분인 거 같은데...(스프링없이 해본 적은 없음...(근데 스프링 없이 하는경우도 있고 테스트는 순수 스프링 없이 가능해야한다고 한다..))

 

필드 인젝을 하면 생성자가 기본생성자 있을텐데... 그럼 나머지 memberRepository랑 bCryptEncoder는 누가 주입을해주지..? 그래 스프링에 종속받지않고 순수 테스트 코드를 작성해야하는데 그럼 어디다가 주입을 하지? 주입을 할 수 있는 코드가 없다.... 그래서 테스트를 위해 생성자주입 및 세터주입을 등록작성한다..? 하나만 하자

 

 

정리

- 생성자 주입을 사용하자. 

- 끝