본문 바로가기
Spring/인프런 토비의 Spring Boot

섹션 7-4 [조건부 자동구성] 커스텀 @Conditional

by include_hoany 2024. 6. 27.

커스텀 @Conditional

@MyAutoConfiguration  
@Conditional(JettyWebServerConfig.JettyCondition.class)  
public class JettyWebServerConfig {  
  
    @Bean("jettyWebServerFactory")  
    public ServletWebServerFactory servletWebServerFactory() {  
        return new JettyServletWebServerFactory();  
    }  
  
    static class JettyCondition implements Condition {  
  
        @Override  
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
            // 현재 jetty class 라이브러리가 존재한다면 true 존재하지 않는다면 false            return ClassUtils.isPresent("org.eclipse.jetty.server.Server",  
                    context.getClassLoader());  
        }  
    }  
  
}

 

@MyAutoConfiguration  
@Conditional(TomcatWebServerConfig.TomcatCondition.class)  
public class TomcatWebServerConfig {  
  
    @Bean("tomcatWebServerFactory")  
    public ServletWebServerFactory servletWebServerFactory() {  
        return new TomcatServletWebServerFactory();  
    }  
  
    static class TomcatCondition implements Condition {  
  
        @Override  
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
            // 현재 Tomcat class 라이브러리가 존재한다면 true 존재하지 않는다면 false            return ClassUtils.isPresent("org.apache.catalina.startup.Tomcat",  
                    context.getClassLoader());  
        }  
    }  
  
}

 

dependencies {  
	// spring boot start web 중  Tomcat만 제외하도록 할 수 있다.
    implementation('org.springframework.boot:spring-boot-starter-web') {  
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'  
    }  
    implementation 'org.springframework.boot:spring-boot-starter-jetty'  
    testImplementation 'org.springframework.boot:spring-boot-starter-test'  
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'  
}

 

 

위처럼 구성하면 Tomcat이 아닌 jetty Servlet Container가 실행되는걸 확인할 수 있습니다.

 

커스텀 메타 Conditional활용

// 커스텀 메타 Conditional 구현  
@Retention(RetentionPolicy.RUNTIME)  
@Target({ElementType.TYPE, ElementType.METHOD})  
@Conditional(MyOnClassCondition.class)  
public @interface ConditionalMyOnClass {  
    // 메타정보를 통해 매개변수를 넘겨줄 수 있도록 한다.  
    String value();  
}

커스텀 Conditional을 구성하여 매개변수로 클래스 정보를 입력하여 존재여부를 체크할 수 있습니다.

 

public class MyOnClassCondition implements Condition {  
    @Override  
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {  
        Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalMyOnClass.class.getName());  
        // 메타정보로 클래스의 경로를 입력받아 해당 클래스가 존재하는지 여부를 체크한다.  
        String value = (String) attrs.get("value");  
        return ClassUtils.isPresent(value, context.getClassLoader());  
    }  
}
@MyAutoConfiguration  
@ConditionalMyOnClass("org.eclipse.jetty.server.Server")  
public class JettyWebServerConfig {  
  
    @Bean("jettyWebServerFactory")  
    public ServletWebServerFactory servletWebServerFactory() {  
        return new JettyServletWebServerFactory();  
    }  
  
}
@MyAutoConfiguration  
@ConditionalMyOnClass("org.apache.catalina.startup.Tomcat")  
public class TomcatWebServerConfig {  
  
    @Bean("tomcatWebServerFactory")  
    public ServletWebServerFactory servletWebServerFactory() {  
        return new TomcatServletWebServerFactory();  
    }  
}

위처럼 구성하면 ConditionalMyOnClass의 매개변수로 전달된 클래스 정보를 토대로 해당 클래스가 존재하는지 확인하여 Bean으로 등록이 가능한지 여부를 체크할 수 있습니다.

현재까지 구성한 커스텀 @Conditional을 정리하면 위와같은 구조를 확인할 수 있습니다.