ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Boot에서 @ComponentScan을 안해도 되는 이유
    Spring 2024. 1. 5. 10:28

    [Spring에서 @ComponentScan 사용하지 않는 경우]

     

    원래 Spring에서는 어떤 클래스들을 @Bean으로 만들지 @Configuration 클래스에 직접 명시를 해줘야한다

    @Configuration
    public class AppConfig {
    
        @Bean
        public MemberRepository memberRepository(){
            return new MemoryMemberRepository();
        }
        
        @Bean
        public MemberService memberService(){
            return new MemberServiceImpl(memberRepository());
        }
    
        @Bean
        public DiscountPolicy discountPolicy(){
            return new RateDiscountPolicy();
        }
        
        @Bean
        public OrderService orderService(){
            return new OrderServiceImpl(memberRepository(),discountPolicy());
        }
    }

     

    하지만 Spring에서 전과 같이 직접 어떤 객체가 Bean으로 등록될지 작성하지 않아도 되게 하는 어노테이션이 있는데

    그게 바로 아래의 @ComponentScan이다.


    [@ComponentScan의 등장]

     

    @ComponentScan을 사용하면 다음과 같이 간단하게 AppConfig를 정의할 수 있다.

    @ComponentScan을 사용한 구성정보 클래스에 아무 코드가 없어도 된다!

    @Configuration
    @ComponentScan(excludeFilters=@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
    public class AppConfig {
        // componentScan 을 사용하므로 @Bean 정의를 안해도 된다
        // Bean 으로 쓸 클래스에 @Component 만 붙여주면 된다
    }

     

    그리고 기존에 @Bean 으로 정의함으로써 각 method 의 객체를 spring container에 bean으로 등록하는 작업

    해당 객체의 클래스에 @Component 를 붙여줌으로써 대체가능하다.

     


    [@Autowired의 등장]

     

    하지만 위와 같이 @ComponentScan만 사용하면 Bean 객체들을 생성해서 Spring Container에 등록만 시키지,

    각 Bean들간의 의존관계를 정립시켜주지는 않는다.

     

    @ComponentScan이 의존관계 주입까지는 해주지 않는다는 것이다!

    따라서 ComponentScan된 Bean 들간 알아서 의존관계 주입이 되게 만들어야하는데 그때 사용하는 것이 @Autowired이다.

     

     

    생성자에 @Autowired를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.

     

    @Component
    public class MyController {
    
        private final MyService myService;
    
        @Autowired
        public MyController(MyService myService) {
            this.myService = myService; // 등록된 Bean 중에서 MyService를 찾아 주입함
        }
    }

     

    자신이 의존하고 있는, 이미 존재하는 객체를 사용해야할때 사용해주면 된다.

     


    [@ComponentScan vs @Autowired]

     

    1. @ComponentScan

    @Component, @Service, @Repository, @Controller 같은 어노테이션이 붙은 클래스를 찾아서 Spring Container에 Bean으로 등록함.

    즉, 어떤 클래스들을 Bean으로 만들지를 결정함

     

    2. @Autowired

    이미 등록된 Bean 중에서 필요한 의존성을 찾아서 주입함

    즉, 어떤 Bean이 어떤 Bean을 필요로 하는지 연결하는 역할

     

    @ComponentScan은 Bean을 등록하는 과정이고, @Autowired는 그 Bean들을 서로 연결(주입)하는 과정입니다.

     


    [의존관계 주입은 생성자로 하는게 가장 좋다]

     

    1. 일단 의존관계 주입은 1번 설정되면 앱이 종료할때까지 바뀌면 안되는 것이고

    2. 생성자는 이러한 목적을 제대로 수행해주는 얘이고

    3. 생성자로 하면 변수에 final 도 사용할 수 있어 더할 나위 없이 안정적인 환경이 구성되기 때문이다.

     


    [SpringBoot에 @ComponentScan 과 AppConfig가 없는 이유?]

     

    근데 Spring Boot 에서는 @ComponentScan과 AppConfig 같은 설정정보 클래스를 만들지 않아도 되는 이유가

    @SpringBootApplication 이라는 어노테이션 자체가 @ComponentScan을 해주기 때문이다!

    @SpringBootApplication

     

    이 어노테이션이 사실 복합 어노테이션인 것이다.

     

    @Target(...)
    @Retention(...)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan
    public @interface SpringBootApplication {
    }

     

    즉, @SpringBootApplication 에는 이미 @ComponentScan이 들어가 있기 때문에

    그래서 SpringBootApplicatin을 붙인 클래스 기준으로 같은 패키지 이하를 자동 스캔하게 된다.

     

    그리고 SpringBootApplication이 된 main 클래스는 Spring Container 전체인 ApplicationContext 자체를 반환하기 때문에

    현재 프로젝트의 Spring Container 내부에 있는 모든 Bean/Component 에 대한 ComponentScan 을 진행하여 스프링 컨테이너에 등록해주는 것이다!

    'Spring' 카테고리의 다른 글

    예외처리 (@RestControllerAdvice + @ExceptionHandler)  (1) 2024.02.05
    @PathVariable vs @RequestParam  (0) 2024.01.28
    스프링 컨테이너와 @Configuration and @Bean  (1) 2024.01.05
    스프링 인터셉터  (0) 2023.12.29
    서블릿 필터  (0) 2023.12.28