Spring @Conditional annotation
개요
@Conditional 어노테이션은 구성 클래스를 스프링 컨테이너로 등록할지 말지 선택할 수 있도록 하는 어노테이션이다.
@Conditional 어노테이션은 Condition 인터페이스 구현체를 속성으로 받고, Condition 인터페이스에는 boolean matches() 메소드가 정의 되어있는데 반환값이 true이면 스프링 컨테이너에 등록하고 false이면 스프링 컨테이너에 등록하지 않게 된다.
Codition 인터페이스의 matches() 메소드는 자바 환경변수를 매개변수로 받을 수 있어서 @Conditional 어노테이션을 사용하면 환경 변수에 따라 다른 빈을 로드하도록 코딩할 수 있다.
Conditional 어노테이션은 Condition 인터페이스를 상속받은 객체들을 속성으로 받는다.
public @interface Conditional {
/**
* All {@link Condition Conditions} that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
Conditional 인터페이스의 matches 메소드는 true, false를 반환한다.
@FunctionalInterface
public interface Condition {
/**
* Determine if the condition matches.
* @param context the condition context
* @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
* or {@link org.springframework.core.type.MethodMetadata method} being checked
* @return {@code true} if the condition matches and the component can be registered,
* or {@code false} to veto the annotated component's registration
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
@Conditional 어노테이션
Conditional 어노테이션은 조건에 따라 자바 설정 클래스를 선택할 수 있게 해주는 어노테이션이다. 이를 사용하면 환경변수 설정 값으로 빈으로 등록할 POJO 클래스를 선택할 수 있다.
Student와 Teacher라는 두 개의 POJO 클래스가 있고, 이 클래스들은 Person이라는 인터페이스를 타입로 갖는다. 그리고 우리는 Person이라는 타입으로 빈을 불러 올 수 있다. 이때, Person이라는 빈이 Student가 될지 Teacher가 될지 환경변수를 지정하여 선택해보자.
먼저 빈의 타입이 되는 Person 인터페이스와 이를 빈으로 등록할 Teacher와 Student POJO를 정의한다.
public interface Person {
String getJob();
}
@Component
public class Teacher implements Person{
@Override
public String getJob() {
return "My job is teacher";
}
}
@Component
public class Student implements Person{
@Override
public String getJob() {
return "My job is student";
}
}
그 다음에는 Student와 Teacher POJO에 @Conditional 어노테이션을 사용하여 어떤 Person 타입이 빈으로 등록될지 선택되게 만들자. @Conditonal 어노테이션은 타입으로 Condition 인터페이 구현체를 받으며, 이 Condition 인터페이스는 matchers라는 메소드의 반환값을 통해 해당 클래스가 빈으로 등록될지 말지 여부를 결정한다.
@Component
@Conditional(StudentConditional.class)
public class Student implements Person{
@Override
public String getJob() {
return "My job is student";
}
}
public class StudentConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// True이면 빈으로 등록
// 자바 클래스파일이나 Jar 파일을 실행할때, -Dperson=student 를 입력하면 Student 빈이 등록됨!
return "student".equals(context.getEnvironment().getProperty("person"));
}
}
@Component
@Conditional(TeacherConditional.class)
public class Teacher implements Person{
@Override
public String getJob() {
return "My job is teacher";
}
}
public class TeacherConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// True이면 빈으로 등록
// 자바 클래스파일이나 Jar 파일을 실행할때, -Dperson=teacher 를 입력하면 Person 빈이 등록됨!
return "teacher".equals(context.getEnvironment().getProperty("person"));
}
}
마지막으로 테스트를 해보자. @Conditonal이 사용된 코드를 바로 작동시키려고 하면 오류가 발생한다. 꼭 환경변수를 넣어주자. ex) java -Dperson=teacher -jar filename.jar argumenets | java -Dperson=teacher filename.class argumenets |
public static void main(String[] args) {
Package pack = ConditionalTestMain.class.getPackage();
AnnotationConfigApplicationContext context = newAnnotationConfigApplicationContext();
context.scan(pack.getName());
context.refresh();
Person person = context.getBean(Person.class);
System.out.println(person.getJob());
}
콘솔 출력
My job is teacher
firewood3’s GitHub : Spring @Conditional annotataion
참고자료
java 명령어의 옵션 정리
참고도서
제목: 스프링 부트로 배우는 자바 웹 개발
지은이: 윤석진
펴낸곳: 제이펍