기본부터 다지는 Spring(udemy 참고) Ch02.정리

khyojun·2023년 12월 16일
1
post-thumbnail

이전 질문들에서 아직 해결하지 못했던 2가지 문제가 있다.

  • 질문 5: Spring은 객체를 관리하고 오토 와이어링을 수행하고 있습니다.
    그런데 우리는 객체를 생성하기 위한 코드를 작성하고 있지 않나요?
    Spring에게 객체를 생성하도록 어떻게 하나요?
  • 질문 6: Spring이 정말로 모든 것을 쉽게 만들고 있는 건가요?

이 문제들을 어떻게 대답할 수 있는지 확인해보고자 한다!

시작하기 이전, @ComponentScan, @Component

이전 코드를 작성하는데 있어서 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을 활용한다.

그러면 다음과 같이 된다. 기본적으로 찾으려고 하는 곳에서

📁 GamingAppLauncher

@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();
        }
        
    }
}

📁 MarioGame

@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가지 방법이 있다.

  • 생성자 주입
  • setter 주입
  • field 주입

아까 위와 같이 @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;
    }
}

setter 주입

    @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;
    }

field 주입

        @Autowired
        Dependency1 dependency1;
        @Autowired
        Dependency2 dependency2;

3가지에 대해서 언급할 말이 있지만 Spring Team에서는 생성자 주입을 가장 추천한다!

왜냐하면 객체 생성시 바로 의존성을 초기화하여 진행하기 때문이다!

@Component만 쓸 거냐?

사실 이 질문에 대해서 6번의 답변이 됬다고 말하긴 했는데 조금 생각해보면 @Bean을 사용해야할 때도 있을 거다. 강의에서는 바로 Spring Security와 같이 3rd-party의 객체를 사용하게 되었을 때라고한다.

ex) 내가 Spring Security 코드에 함부로 @Component를 달 수 있나? 그렇지 않다. 그렇기 때문에 따로 빼내서 빈을 등록하여 사용해야 한다.

이 점을 유의하며 사용해야한다.

그렇지만 사실 일반적으로는 @Component 사용하는게 IoC의 방식으로 진행하는 방식이라는 것을 기억하고 사용하는게 좋다.

출처

profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글