이전 질문들에서 아직 해결하지 못했던 2가지 문제가 있다.
- 질문 5: Spring은 객체를 관리하고 오토 와이어링을 수행하고 있습니다.
그런데 우리는 객체를 생성하기 위한 코드를 작성하고 있지 않나요?
Spring에게 객체를 생성하도록 어떻게 하나요?- 질문 6: Spring이 정말로 모든 것을 쉽게 만들고 있는 건가요?
이 문제들을 어떻게 대답할 수 있는지 확인해보고자 한다!
이전 코드를 작성하는데 있어서 Bean을 등록하는데 어떤 고생을 하였는지 예제를 통해 확인하자.
@Configuration
public class GameConfig {
@Bean
@Primary
public GamingConsole game(){
return new MarioGame();
}
@Bean
@Qualifier("pacman")
public GamingConsole game2(){
return new PacmanGame();
}
@Bean
//@Primary
public GameRunner gameRunner(){
return new GameRunner(game());
}
@Bean
@Primary
public GameRunner gameRunner2(@Qualifier("pacman") GamingConsole game){
return new GameRunner(game);
}
다음과 같이 진행을 했어야 했다. 사실 이 코드는 프로그래머가 어떤 Bean을 주입하기 위해 작성했다고 할 수 있다. 그래서 어찌보면 등록될 객체를 해야한다는 것을 알고 있다.
그래서 추가적으로 Spring에서 자동적으로 객체를 주입할 수 있게 해주는 @Component, @ComponentScan
을 활용한다.
그러면 다음과 같이 된다. 기본적으로 찾으려고 하는 곳에서
@ComponentScan("com.example.learnspringframework.game")
public class GamingAppLauncher {
public static void main(String[] args) {
try(var context = new AnnotationConfigApplicationContext(GamingAppLauncher.class)
){
context.getBean(GamingConsole.class).up();
context.getBean(GameRunner.class).run();
}
}
}
@Component
@Primary
public class MarioGame implements GamingConsole{
public void up(){
System.out.println("Jump");
}
public void down(){
System.out.println("Go into a hole");
}
public void left(){
System.out.println("Go left");
}
public void right(){
System.out.println("Accerlate");
}
}
다음과 같이 진행하였을 때 진행이 되어진다. 해당하는 패키지 기준 아래까지 있는 @Component를 찾아서 빈을 등록하게 되어진다.
이렇게 진행이 되면 즉, 아까의 빈을 주입했던것과 달리 상당히 코드가 간단해졌다는 것을 알 수 있음을 통해 질문 6번에 대한 답변이 되어졌다고 생각한다.
추가로 @Primary, @Qualifier 도 이전과 같은 원리로 적용이 되니 참고하자!(구체적인게 더 우선순위가 높다. 그러므로 @Qualifier가 더 높다.)
여기서 @ComponentScan에 경로를 적지않고 생략하면 자신의 클래스에 속해있는 패키지를 자동으로 지정하게 된다!
크게 3가지 방법이 있다.
아까 위와 같이 @Autowired
라는 속성을 통해서 어떤 의존성이 있는지 확인하게 해준다.
@Component
class YourBuisnessClass {
Dependency1 dependency1;
Dependency2 dependency2;
@Autowired // 생성자 주입(생략해도 생성자 주입 자동으로 한다!) Spring 팀은 생성자 주입을 추천한다! 모든 초기화가 하나의 메서드에서 일어나기 때문 -> 그래서 객체 생성시 바로 주입하게 설정
public YourBuisnessClass(Dependency1 dependency1, Dependency2 dependency2) {
System.out.println("Constructor Injection - buisness");
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}
}
@Autowired // setterInjection
public void setDependency1(Dependency1 dependency1) {
System.out.println("Setter Injection - setDepen1");
this.dependency1 = dependency1;
}
@Autowired
public void setDependency2(Dependency2 dependency2) {
System.out.println("Setter Injection - setDepen2");
this.dependency2 = dependency2;
}
@Autowired
Dependency1 dependency1;
@Autowired
Dependency2 dependency2;
3가지에 대해서 언급할 말이 있지만 Spring Team에서는 생성자 주입을 가장 추천한다!
사실 이 질문에 대해서 6번의 답변이 됬다고 말하긴 했는데 조금 생각해보면 @Bean을 사용해야할 때도 있을 거다. 강의에서는 바로 Spring Security와 같이 3rd-party의 객체를 사용하게 되었을 때라고한다.
ex) 내가 Spring Security 코드에 함부로 @Component를 달 수 있나? 그렇지 않다. 그렇기 때문에 따로 빼내서 빈을 등록하여 사용해야 한다.
이 점을 유의하며 사용해야한다.
@Component
사용하는게 IoC의 방식으로 진행하는 방식이라는 것을 기억하고 사용하는게 좋다.