본문 바로가기
Spring

@Conditional과 @AutoConfiguration

by 혀눅짱 2023. 11. 6.

@Conditional

  • 같은 소스 코드인데 특정상황일때만 특정 빈들을 등록해서 활성화 시켜주는 기능
  • Condition 인터페이스를 구현해서 matches 메소드의 결과가 true면 동작 false면 동작하지 않는다.

 

 

예시를 보자.

@Slf4j
public class MemoryCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //-Dmemory=on
        String memory = context.getEnvironment().getProperty("memory");
        log.info("memory={}", memory);
        return "on".equals(memory);
    }
}

 

 

@Configuration
@Conditional(MemoryCondition.class)
public class MemoryConfig {

    @Bean
    public MemoryController memoryController(){
        return new MemoryController(memoryFinder());
    }

    @Bean
    public MemoryFinder memoryFinder(){
        return new MemoryFinder();
    }
}

 

@Slf4j
public class MemoryFinder {

    public Memory get(){
        long max = Runtime.getRuntime().maxMemory();
        long total = Runtime.getRuntime().totalMemory();
        long free = Runtime.getRuntime().freeMemory();
        long used = total - free;
        return new Memory(used,max);
    }

    @PostConstruct
    public void init(){
        log.info("init memoryFinder");
    }
}

 

 

@Slf4j
@RequiredArgsConstructor
@RestController
public class MemoryController {

    private final MemoryFinder memoryFinder;

    @GetMapping("/memory")
    public Memory system() {
        Memory memory = memoryFinder.get();
        log.info("memory={}", memory);
        return memory;
    }
}

 

 

환경변수 memory의 밸류가 on이면 해당 멤버컨트롤러와 멤버파인더의 빈들을 등록한다.(참고로 프로젝트 패키지가 다르기때문에 멤버컨트롤러랑 멤버파인더는 전혀다른 별도의 모듈이다)

 

 

 

 

인텔리제이 설정에서 memory 환경변수를 on 으로 설정하여 구동하면 정상적으로 멤버컨트롤러에서 설정한 요청에 대한 응답이 출력되지만 환경변수의 값이 다를경우 빈으로 등록되지 않아서 없는 요청으로 에러가 발생된다.

 

 

해당 컨디션 인터페이스를 구현할 필요도없이 자체적인 @Conditinal 의 부가 어노테이션들이 있다.

@ConditionalOnProperty(name = "memory", havingValue = "on")

 

해당 어노테이션을 @Conditional 대신 사용하면 방금 condition 인터페이스를 구현한 것과 같은 효과를 준다.

 

name 속성 => 환경변수 키

value 속성 => 환경변수 값

 

그밖에 부가적이 어노테이션의 목록이다.

 

@ConditionalOnClass , @ConditionalOnMissingClass
클래스가 있는 경우 동작한다. 나머지는 그 반대 
@ConditionalOnBean , @ConditionalOnMissingBean
빈이 등록되어 있는 경우 동작한다. 나머지는 그 반대
@ConditionalOnProperty
환경 정보가 있는 경우 동작한다. 
@ConditionalOnResource
리소스가 있는 경우 동작한다.
@ConditionalOnWebApplication , @ConditionalOnNotWebApplication
웹 애플리케이션인 경우 동작한다.
@ConditionalOnExpression
SpEL 표현식에 만족하는 경우 동작한다.

 

 

@AutoConfiguration

 

스프링 부트 자동 구성이 동작하는 방식은 다음 순서로 확인할 수 있다.

@SpringBootApplication ->

@EnableAutoConfiguration ->

@Import(AutoConfigurationImportSelector.class) ->

 resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일열어서 설정정보 선택 ->

해당 파일의 설정 정보가 스프링 컨테이너에 등록되고 사용

 

 

AutoConfiguration 은 라이브러리를 만들어서 제공할 때 사용하고, 그 외에는 사용하는 일이 거의 없다.

왜냐하면 보통 필요한 빈들을 컴포넌트 스캔하거나 직접 등록하기 때문이다. 하지만 라이브러리를 만들어서 제공할 때는 자동 구성이 유용하다. 실제로 다양한 외부 라이브러리들이 자동 구성을 함께 제공한다.
보통 이미 만들어진 라이브러리를 가져다 사용하지, 반대로 라이브러리를 만들어서 제공하는 경우는 매우 드물다. 그럼 자동 구성은 왜 알아두어야 할까?

자동 구성을 알아야 하는 진짜 이유는 개발을 진행 하다보면 사용하는 특정 빈들이 어떻게 등록된 것인지 확인이 필요할 때가 있다. 이럴 때 스프링 부트의 자동 구성 코드를 읽을 수 있어야 한다. 그래야 문제가 발생했을 때 대처가 가능하다. 자동화는 매우 편리한 기능이지만 자동화만 믿고 있다가 실무에서 문제가 발생했을 때는 파고 들어가서 문제를 확인하는 정도는 이해해야 한다. 이번에 학습한 정도면 자동 구성 코드를 읽는데 큰 어려움은 없을 것이다.

 

 

 

 

 

 

'Spring' 카테고리의 다른 글

Redis와 SpringBoot 연동  (1) 2023.11.20
SpringBoot AutoConfiguration  (0) 2023.11.06
SpringBoot와 웹서버  (0) 2023.10.31
인터셉터 설정  (0) 2023.10.05
전역예외처리  (1) 2023.10.05