-

[스프링부트 Step 12] - 자바 코드로 직접 스프링 빈 등록하기 본문

백엔드 기술 정리/스프링 부트

[스프링부트 Step 12] - 자바 코드로 직접 스프링 빈 등록하기

흣차 2022. 1. 4. 03:13
728x90
반응형

이전에 해본건 @Service, @Repository, @Autowired 등을 사용해서 컴포넌트 스캔으로 자동 등록하고 사용했었는데 이걸 수동으로 스프링 빈에 등록하는걸 아는 것이 좋아서 기록을 하게 되었습니다.

어노테이션을 사용하면 정말 편리하겠지만 그러지 못한 상황이 발생했을 때의 경우를 대비해서 우리는 직접 등록해야 합니다.

결국 2가지 모두 다 알고 있어야겠습니다.

MemberService 클래스에서

@Autowired를 제거해줍니다.

그리고 MemoryMemberRepository에서도 @Repository를 지웁니다.

단, MemberController는 그대로 어노테이션을 유지합니다.

이대로 실행을 하면 당연히 MemberService가 등록이 안되어 있는데 우리가 

MemberController에서 MemberService를 사용하려 했으므로 의존성 주입이 안일어나게 되어 오류가 뜹니다.

자 그래서 직접 빈에 등록을 할 것입니다.

그래서 SprintConfig라는 클래스를 만들고 그 위에 @Configuration어노테이션을 걸고 이렇게 작성합니다.

이렇게 하면 빈에 자동으로 MemberService가등록이 됩니다.

근데 MemberService에는 MemberRepository를 넣고 실행했었습니다. 그래서

이렇게 작성해야 문제 없이 의존성 주입한 상태로 MemberService와 MemberRepository를 빈에 등록할 수 있습니다.

그러면서

MemberService는 MemberRepository를 사용할 수 있고 (@Autowired 사용할때와 동일하게) 위의 사진처럼 의존성 주입이 일어나게 됩니다.

그런데 왜 MemberController는 따로 어노테이션을 제거하지 않았을까요?

보통 Controller는 스프링이 직접 관리합니다.

따라서 그냥 두면 컴포넌트 스캔으로 올라가고 @Autowired로 지정해주면 MemberService만 따로 빈에 등록해주어도 자동으로 MemberController에서 MemberService를 인식합니다.

위의 사진처럼 말이죠.

따로 SpringConfig에 MemberController를 빈에 등록하지 않아도 MemberService만 등록해있다면 일반적으로 @Controller라는 어노테이션을 사용함으로써 스프링에 등록할 수 있습니다.

아무래도 Controller는 빈에 직접 등록하는 일은 거의 없는 것 같습니다.

 

어떤게 편하신가요???

당연히.. 첫 번째 방법이 편하죠?? 근데 둘 다 각자 장단점이 존재합니다. 

한 번 살펴보겠습니다.

과거에는 XML이라는 문서로 이러한 설정을 했었습니다.

하지만 지금은 XML을 거의 사용하지 않는 추세이고 자바 코드로 설정을 많이 합니다.

상당히 편리해졌다고 볼 수 있겠네요.

 

그리고 DI에는 필드 주입, Setter 주입, 생성자 주입이라고 3가지가 있습니다.

이제 이런거 보면 MemberController 안에 MemberService를 새로 생성해서 주입하고 있습니다.

이를 DI 중에서 생성자 주입이라고 얘기합니다. 

그 다음에 생성자를 빼고 필드에다가 바로 등록하는걸 필드 주입이라고 하는데요. 

예를들면

이런식으로 필드에 바로 생성해버리는걸 필드 주입이라고 합니다.

근데 왼쪽 밑에 물결표시가 뜨는데 살펴보면 create Constuctor이런거도 뜨는걸 보면 딱히 권장하는 방법이 아닐 때 자주 등장합니다. 실제로 좋은 방법은 아닙니다.

왜냐하면 이렇게 지정해놓으면 객체를 바꿀 수 있는 방법이 없기 때문입니다.

자주 사용되는 방법은 아니고 반드시 안바뀔 요소들에 한정해서 이루어져야 겠습니다.

 

마지막으로 Setter주입이 있습니다.

이런 경우에는 단점이 존재하는데, 누군가가 MemberController를 요청했을 때 Public으로 열려있어야 합니다.

그래서 setMemberService를 중간에 바꿔치기를 할 이유가 없지만 이게 public하게 노출이 됩니다.

보통 중간에 바꾸면 문제가 생길 요소가 다분해집니다.

다른 개발자들과 협어하는데 계속해서 변경되면 안되니까요.(누군가가 바꿀 수 있으니 막아놔야함)

그래서 제일 좋은건 생성자 주입이 가장 좋다고 여겨지고 있습니다.

만약 앱이 실행이 조립이 된다면 그 시점에 MemberController에 한 번 들어오고 끝이라서 깔끔하게 생명주기가 끝날 수 있습니다.

 

자 그래서 지금까지 배웠던 중요한 사실을 복습해보겠습니다.

1. XML로 설정하는 방식도 있지만 최근에는 잘 사용하지 않으므로 생략합니다.

2. DI에는 필드 주입, 생성자 주입, Setter 주입이 있습니다. 의존관계가 실행중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 주로 사용합니다.

3. 실무에서는 주로 정형화된 Controller, Service, Repository같은 코드는 컴포넌트 스캔을 사용합니다. 그리고 정형화 되지 않은 코드는 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈에 등록합니다.

4. @Autowired를 통한 DI는 스프링이 관리하는 객체에서만 동작합니다. 스프링 빈에 등록하지 않고 내가 직접 생성한 객체에서는 통하지 않습니다.

이 3번의 경우가 이번 포스팅의 핵심입니다.

예전에 설명드렸지만 우린 아직 DB를 결정하지 않은 상태에서 진행중입니다.

그래서 MemoryMemberRepository가 인터페이스로 개발되었습니다.

DB가 만약 고심 끝에 선정되었다면 이 DB를 연결을 정말 기가막히게 쉽게 할 수 있게 하기 위해서 인터페이스를 사용했다고 역시 말씀드렸습니다.

어떻게 하냐면, 빈에 등록된 public MemoryMemberRepository를 return할 때 Memory로 반환하는게 아니라, DBMemoryMemberRepository로 반환하면 정말 손쉽게 교체할 수 있습니다.

감사합니다!

728x90
반응형
Comments