스프링 공부/인프런 김영한 스프링 입문 노트정리

4-2. 자바 코드로 직접 스프링 빈 등록하기

모항 2022. 7. 29. 20:13

저번 시간에

어노테이션을 이용하여

콩 아주머니가 알아서 콩 설계도를 긁어모으도록 하는 법을 배웠다면,

 

이번엔 우리가 직접 콩 설계도 목록을 별도의 코드 파일로 마련하는 법을 배울 것이다.

 

그러므로 저번 시간에 넣어줬던

@Service, @Repository, @Autowired를 모두 지워준다.

단, 컨트롤러에 있는 어노테이션들은 지우지 말고 둬야 한다!

여기 있는 @Controller와 @Autowired는 가만히 둬야 한다!

 

 

어노테이션들을 싹 지우고 어플리케이션을 실행해보면

필요한 bean이 정의되어있지 않다는 메시지와 함께 빌드가 실패한다. 그럼 준비 끝이다.

 

 

 

 

SpringConfig 파일 작성하기

여기다 SpringConfig라는 이름의 새 java class를 하나 만든다.

 

 

 

이 클래스에는 @Configuration이라는 어노테이션을 붙인다.

이 클래스가 콩 설계도 목록이란다 라는 뜻이다.

 

 

각각의 콩에 대한 정보 앞에는 @Bean을 붙이고

올바른 콩 객체를 리턴하는 로직을 작성해준다.

 

이렇게만 해주면 의존관계 설정까지 한 번에 끝난다.

왜냐하면,

memberRepository()의 결과물인 MemoryMemberRepository 구현체 객체가

memberService 실행 시에 재료로 들어가도록 명시해주었기 때문이다.

 

 

이제 다시 애플리케이션을 실행해보면 문제 없이 잘 돌아간다.

 

저번 시간에 배웠던 방식과 다르지만

결과물은 같다!

 

 

 

 

 

 

두 방식의 장단점

저번 시간에 배운 컴포넌트 스캔 방식과

이번 시간에 배운 자바 코드로 설정하는 방식은 서로 다른 장단점을 가진다.

 

그리고 우리는 이번 어플리케이션을 만드는 동안, 자바 코드로 설정하는 방식을 선택할 것이다.

그 이유는 장단점을 살펴보면 알 수 있다.

 

컴포넌트 스캔 방식의 장점

편리하다.

이미 만들어놓은 코드에다 어노테이션 몇 개만 붙여주면 끝이기 때문이다.

컴포넌트 스캔 방식의 단점

컴포넌트 구조나 의존 관계를 변경해야 할 경우,

내가 직접 코드를 뒤져보며 어노테이션을 고치거나

코드의 내용 자체를 수정해야 한다.

자바 코드 방식의 장점

컴포넌트 구조나 의존 관계를 변경해야 할 경우,

기존 코드를 거의 건드리지 않고, config 클래스의 내용만 바꾸면 된다.

자바 코드 방식의 단점

새 클래스를 만들어서 내용을 채워넣어야 하기 때문에 컴포넌트 스캔보다는 살짝 귀찮다.

 

 

 

우리가 만들고 있는 회원 관리 어플리케이션에 대하여 소개해주셨던

 

회원 관리 예제 - 백엔드 개발: 비즈니스 요구사항 정리

다음 강의부터 실제 예제를 만들어보는 과정이 시작된다. 이번 강의에서는 앞으로 만들 예제에 대해서 간단하게 설명해주셨다. 예제에 대하여 우리가 만들 프로그램은 매우 단순하다. 프로그램

blowupmomo.tistory.com

이 강의 내용을 보면,

어떤 종류의 DB(데이터 저장소)를 사용할지 정해지지 않은 상황이라고 가정하고 개발을 진행

한다고 되어있다.

 

따라서 우리는

무슨 DB를 사용할지 나중에 정해서

현재 임시 DB 역할을 해주고 있는 놈을 없애고 그 자리에 진짜 DB를 갈아끼워줘야 한다.

 

그러려면 컴포넌트 스캔 방식보다는 자바 코드를 사용하는 게 적합하다.

 

실무에서는

정형화된 컴포넌트인 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔 방식으로 빈 등록을 하고

정형화되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면, 자바 코드로 직접 빈 등록을 한다.

 

 

 

 

 

 

 

DI의 세 가지 방법

DI(Dependency Injection), 의존성 주입에는 필드 주입, setter 주입, 생성자 주입 총 세 가지 방법이 있다.

편하게 정리하기 위해,

의존을 하고 있는 클래스를 A라고 하고, 의존당하는 클래스를 B라고 하겠다.

 

 

1. 필드 주입

이런 식으로 의존 관계를 표시해주는 방법이다.하지만 이것은 캡처에서 @Autowired에 노란 줄이 그어졌다는 것을 보면 알 수 있듯이 IntelliJ 자체적으로도 권장하지 않는,별로 좋지 않은 방법이다.

 

왜냐하면 특정 A 객체에 짝지을 특정 B 객체가 어떤 것이 될지 내가 지정할 수가 없기 때문이다.

 

 

2. setter 주입

A 내부에 생성자가 아닌 일반 setter 메소드를 만들어놓고,그 메소드를 이용하여 언제든지 B 객체를 A에다가 주입할 수 있게 하는 방식이다.

 

하지만 이것도 별로 좋지 않은 방법이다.setter 메소드는 그 태생 자체가 객체의 외부에서 접근하여 객체의 필드를 바꾸는 메소드이기 때문에,public한 일반 메소드로 만들어진다.

 

그렇기 때문에 setter 메소드를 언제든 어디서든 호출하여 의존 관계를 바꿀 수 있고프로그램이 실행되는 와중에 동적으로 바뀌도록 코드를 짤 수도 있다.

 

그러나 의존 관계라는 것은 그리 쉽게 휙휙 바뀌는 것이 아니다.

특히 실행 도중 동적으로 바뀌는 경우는 거의 없다. 강사님의 말씀에 따르면 아예 없다고 해도 무방하다.

의존 관계가 바뀌어야 할 때에는 차라리 config 파일을 직접 수정한 뒤에 서버를 닫았다 다시 열지, 서버가 열린 와중에 동적으로 바꾸는 기능을 만들거나 사용하지는 않는다.

 

바뀌지 않아야 할 의존 관계가 의도치 않게 바뀌어버려 문제가 될 가능성이 훨씬 크다.

 

 

 

3. 생성자 주입

내가 코테 할 때 맨날 썼던 그 방법이자,

이 강의에서도 계속 써온 방법이다.

A의 객체를 새로 만들 때 사용하는 생성자 메소드의 매개변수로 B 객체를 넣어주는 방식이다.

 

이 방법이 가장 권장된다.

처음에 A 객체를 새로 만들 때 내가 원하는 B 객체를 매치시킬 수 있고,

이때 최초로 만들어진 의존 관계가 이후 손쉽게 변경될 일이 없기 때문이다.

 

1번과 2번의 단점을 모두 보완했다고 볼 수 있다.

 

 

 

 

 

 

 

 

@Autowired 사용시 주의점

@Autowired를 통한 DI는 빈 등록이 된 객체에서만 동작한다.

 

컴포넌트 스캔이든 config 클래스로 직접 올리든

무조건 스프링이 빈으로서 관리하고 있어야만 그 내부의 @Autowired가 동작한다.

 

스프링 빈으로 등록하지 않고 내가 그냥 직접 생성한 객체에서는 동작하지 않는다.

 

 

 

 

스프링 컨테이너와 DI에 대한 더 자세한 설명은 스프링 핵심 원리 강의에서 해주신다고 한다.