스프링을 배우다 보면 문득 이런 생각이 듭니다.
"스프링이 객체를 관리해준다며? 근데 왜 내가
@Bean만들고new PacmanGame()이러고 있지?"
맞습니다. 지금까지 우리는 스프링에게 "이거 만들어줘"라고 일일이 주문서(Configuration)를 써서 줬습니다. 하지만 이번에는 주문서조차 필요 없는, 진짜 스프링의 마법을 배우겠습니다.
오늘 배운 내용을 아주 쉽게 3단계로 배워봅시다.
@Component지금까지 우리는 설정 파일(Configuration)에다가 이렇게 적었습니다.
PacmanGame이라는 빈(Bean)을 하나 만들어." (수동 등록)하지만 이제는 클래스 자체에다가 이름표를 딱 붙여버립니다.
@Component // <-- "스프링아, 나 여기 있어! 나를 빈으로 만들어줘!"
public class PacmanGame implements GamingConsole {
// ... 게임 내용 ...
}
이렇게 PacmanGame 클래스 머리 위에 @Component만 붙이면, 우리가 설정 파일에 일일이 등록하지 않아도 스프링이 "어? 여기 컴포넌트가 있네? 내가 객체로 만들어야지" 하고 알아서 생성합니다.
이것이 바로 컴포넌트(Component)입니다.
@ComponentScan그런데 @Component만 붙이고 실행하면 에러(NoSuchBeanDefinitionException)가 빵 터집니다.
스프링: "야, 객체 만들라며? 근데
PacmanGame이 어디 있는데? 난 못 찾겠어!"
스프링은 기본적으로 어디를 뒤져야 할지 모릅니다. 그래서 "어느 동네를 뒤져야 하는지" 알려줘야 합니다.
@Configuration
@ComponentScan("com.in28minutes.learningspringframework.game") // <-- "이 패키지 안을 샅샅이 뒤져봐!"
public class GamingAppLauncherApplication {
// ...
}
@ComponentScan은 스프링에게 "이 패키지(폴더) 안에 들어가서 @Component 붙은 애들을 싹 다 찾아서 객체로 만들어!"라고 명령하는 것입니다.
이제 스프링은 해당 패키지를 스캔하고, 숨어있던 PacmanGame을 찾아내서 빈(Bean)으로 등록합니다.
가장 놀라운 점은 GameRunner도 똑같이 처리할 수 있다는 겁니다.
@Component // 너도 빈이 되어라
public class GameRunner {
private GamingConsole game;
public GameRunner(GamingConsole game) { // 생성자
this.game = game;
}
// ...
}
이렇게 해두면 스프링이 일을 하는 순서는 다음과 같습니다.
@ComponentScan이 가리키는 패키지를 뒤진다.PacmanGame에 붙은 @Component를 발견하고 객체를 만든다.GameRunner에 붙은 @Component를 발견하고 객체를 만들려고 보니... 어라? 생성자에 GamingConsole이 필요하네?PacmanGame이 있잖아!" 하고 알아서 GameRunner 안에 PacmanGame을 쏙 넣어줍니다. (자동 와이어링)우리는 new GameRunner(new PacmanGame()) 같은 코드를 단 한 줄도 쓰지 않았습니다.
코드가 엄청나게 줄어들 수 있습니다. 오늘 핵심은 "스프링에게 권한 위임하기"입니다.
@Bean 만들 필요 없음!)혹시 코드가 작동하지 않는다면?
@Component를 빼먹지 않았나요?@ComponentScan에 적은 패키지 경로가 정확한가요?다음 시간에는 @Component가 여러 개라면 스프링이 어떻게 반응할지 알아보겠습니다.