ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1. Auto-configure 을 이해하고 디버깅 할 수 있다
    스프링개발자/202 - 디버깅+테스팅 2020. 8. 14. 00:34

    스프링부트 공식 문서에 따르면, Autoconfiguration 의 정의는 다음과 같다. 

     

    16. Auto-configuration
    Spring Boot auto-configuration attempts to automatically configure your Spring application
    based on the jar dependencies that you have added. For example, If HSQLDB is on your classpath,
    and you have not manually configured any database connection beans, 
    then we will auto-configure an in-memory database.
    You need to opt-in to auto-configuration by adding the @EnableAutoConfiguration or 
    @SpringBootApplication annotations to one of your @Configuration classes.
    
    [Tip]
    You should only ever add one @EnableAutoConfiguration annotation. 
    We generally recommend that you add it to your primary @Configuration class.
    
    의역
    
    스프링부트 어플리케이션에 사용되는 구성요소들을 자동으로 셋업해준다;
    개발자가 classpath에 있는 dependency의 bean을 일일히 configure 하지 않아도
    스프링부트 auto-configuration을 통해서 해당 bean를 사용 할 수 있다.
    다음의 어노테이션을 통해서 사용가능하다
    @EnableAutoConfiguration, @SpringBootApplication
    어노테이션 @EnableAutoConfiguration은 메인에 한번만 선언하면 된다.

     

    1. EnableAutoConfiguration의 역할

    package me.ndPrince.routeOptimization;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class RouteOptimizationApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(RouteOptimizationApplication.class, args);
    	}
    
    }
    

    스프링부트 어플은 메인에 다음 어노테이션이 꼭 있다. @SpringBootApplication

    어노테이션을 Ctrl+클릭 하는 것은 좋은 습관인데, 그 안에 포함하고 있는 역할들을 볼 수 있어서이다.

    import에서 보면, 해당 어노테이션은 autoconfigure 패키지에서 온걸 확인할 수 있다.

     

    @SpringBootApplication 어노테이션은 다음의 어노테이션을 포함하고 있다.

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    public @interface SpringBootApplication {
    ...

    @EnableAutoConfiguration을 통해 auto-configure 기능을 enable하고

    @ComponentScan을 통해서 auto-configure를 할 대상 component들을 스켄한다.

    ExcludeFilter에 의해 filter out 되는 클래스를 제외한 모든 component들이 자동등록되는 대상이다.

     

    2. 컴포넌트가 뭘까? What is a component?

    What is a component? [출처: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html]
    
    Indicates that an annotated class is a "component". 
    Such classes are considered as candidates for auto-detection 
    when using annotation-based configuration and classpath scanning.
    Other class-level annotations may be considered as identifying 
    a component as well, typically a special kind of component: e.g. 
    the @Repository annotation or AspectJ's @Aspect annotation.
    
    "컴포넌트는" 클래스 딴에 붙이는 일반적인 어노테이션으로, 
    auto-configuration의 대상이 된다.
    마찬가지의 역할을 하는 다른 클래스 대상의 어노테이션은
    @Repository 와 AspectJ's의 @Aspect 어노테이션 등이 있다.

    컴포넌트와 빈의 차이를 알고 넘어가면 좋다

    빈은 메소드 단에, 컴포넌트는 클래스 단에 적용된다.

     

    3. 어떤 어노테이션들이 @Component 일까?

    자동등록되는 모든 어노테이션이 결국엔 @Component를 가지고 있다.

    일례로, 우리 코드에 DispatchController @RestController 어노테이션을 보면,

    package me.ndPrince.routeOptimization;
    
    import me.ndPrince.routeOptimization.model.DispatchRequest;
    import me.ndPrince.routeOptimization.model.DispatchResponse;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.validation.Valid;
    
    @RestController
    @RequestMapping(value = "/dispatch")
    public class DispatchController {
    
        @PostMapping
        public DispatchResponse postDispatchRequest(@Valid @RequestBody DispatchRequest request){
            return new DispatchResponse();
        }
    }
    

    @RestContoller를 Ctrl+클릭 하자

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Controller
    @ResponseBody
    public @interface RestController {
    
    	/**
    	 * The value may indicate a suggestion for a logical component name,
    	 * to be turned into a Spring bean in case of an autodetected component.
    	 * @return the suggested component name, if any (or empty String otherwise)
    	 * @since 4.0.1
    	 */
    	@AliasFor(annotation = Controller.class)
    	String value() default "";
    
    }

    @Controller를 Ctrl+클릭 하자

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
    
    	/**
    	 * The value may indicate a suggestion for a logical component name,
    	 * to be turned into a Spring bean in case of an autodetected component.
    	 * @return the suggested component name, if any (or empty String otherwise)
    	 */
    	@AliasFor(annotation = Component.class)
    	String value() default "";
    
    }

    @RestController는 @Controller의 한 종류이고, @Controller는 결국엔 @Component임을 알 수 있다.

    같은 방식으로 @Service, @Repository 등의 어노테이션 또한 결국엔 @Component이고, Autoconfigured 대상이다

     

    어노테이션에 대해 궁금하면 해당 글을 참고하자

    https://2ndprince.tistory.com/24

     

    4. Component를 어떻게 사용할까?

    보통은 autowire를 통해 의존성 주입을 받아서 많이 사용한다.

    Constructor를 통해 주입 받는 방법도 있다.

    Component 의 instance를 우리가 직접 만들고 관리하는게 아니라(new DispatchController())

    스프링부트가 instance를 component 당 하나의 instance 생성하고 같은 객체를 부르는 곳마다 주입시켜준다

    내가 관리 해야 될게, 스프링부트가 대신 해준다고 해서 본 개념을 IoC라고 부른다. (Inversion of Control)

     

    @RestController
    @RequestMapping(value = "/dispatch")
    public class DispatchController {
    
        @Autowired
        private DispatchService dispatchService;
    
        @PostMapping
        public DispatchResponse postDispatchRequest(@Valid @RequestBody DispatchRequest request){
            dispatchService.validate(request);
            return new DispatchResponse();
        }
    }

    new 키워드를 통해 DispatchService의 instance를 생성하지 않고도, autoconfigured된 객체를 스프링으로부터 받아서 사용했다.

     

    다른 학구적인 분석도 가능하지만, 실무에서 이정도만 알아도 충분하다.

Designed by Tistory.