1. Condition과 @Conditional
- 조건에 따라 빈의 등록 여부를 결정. @Bean, @Conponent와 같이 사용
- Condition의 matches()를 구현한 클래스를 @Conditional로 지정
- 조건부 빈 등록
- 개별 빈 : @Bean + @Component + @Conditional
- 빈 여러개(그룹) : @Configuration + @Import + ImportSelector(조건부 결정)
- Starter : 의존 라이브러리 자동관리
- AutoConfiguration : 빈 등록 자동관리
- 그 외의 애너테이션
2. @Import와 ImportSelector
- 조건에 따라 다른 Configuration(자바설정 : 빈 여러개 정의)을 적용할 때 사용
- ImportSelector를 구현하고 이를 @Import하는 애너테이션을 작성해서 적용
@ToString
@Component
@Conditional(TrueCondition.class)
class Engine{}
@ToString
@Component
@Conditional(FalseCondition.class)
class Door{}
class TrueCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
class FalseCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
//@SpringBootApplication // 은 아래의 3개 애너테이션을 붙인것과 동일
@SpringBootConfiguration // @Configuration하고 동일
@EnableAutoConfiguration
@ComponentScan
public class Main {
public static void main(String[] args) {
ApplicationContext ac = SpringApplication.run(Main.class, args);
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
System.out.println("ac = " + ac);
Arrays.sort(beanDefinitionNames); // 빈 목록이 담긴 배열을 정렬
Arrays.stream(beanDefinitionNames) // 배열을 스트림으로 변환
.filter(b->!b.startsWith("org"))
.forEach(System.out::println); // 스트림의 요소를 하나씩 꺼내서 출력
}
@Bean
MyBean myBean(){return new MyBean();}
}
class MyBean{}
- door는 빈등록이 안된 모습...
class OSCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
// System.out.println("System.getProperties() = " + System.getProperties());
return env.getProperty("os.name").equals("Windows 11");
}
}
- System.getProperties()로 os.name이 Windows 11인 Bean들을 뽑아보면...
- engine과 door가 잘 등록이되었다.
- 자바 설정 파일 추가
@ToString
class Car{}
@ToString
class SportsCar extends Car{}
@ToString
class SportsCar2 extends Car{}
@ToString
@Component
@Conditional(OSCondition.class)
class Engine{}
@ToString
@Component
@Conditional(OSCondition.class)
class Door{}
class TrueCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
class OSCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
// System.out.println("System.getProperties() = " + System.getProperties());
return env.getProperty("os.name").equals("Windows 11");
}
}
class MainConfig{ @Bean Car car() {return new Car();} }
class Config1 { @Bean Car sportsCar() {return new SportsCar();} }
class Config2 { @Bean Car sportsCar() {return new SportsCar2();} }
//@SpringBootApplication // 은 아래의 3개 애너테이션을 붙인것과 동일
@SpringBootConfiguration // @Configuration하고 동일
@EnableAutoConfiguration
@ComponentScan
public class Main {
public static void main(String[] args) {
// ApplicationContext ac = SpringApplication.run(Main.class, args);
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class, Config1.class, Config2.class); // 자바 설정을 이용하는 AC
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
System.out.println("ac = " + ac);
Arrays.sort(beanDefinitionNames); // 빈 목록이 담긴 배열을 정렬
Arrays.stream(beanDefinitionNames) // 배열을 스트림으로 변환
.filter(b->!b.startsWith("org"))
.filter(b -> !b.contains("Main"))
.forEach(System.out::println); // 스트림의 요소를 하나씩 꺼내서 출력
System.out.println("ac.getBean(\"sportsCar\") = " + ac.getBean("sportsCar"));
}
@Bean
MyBean myBean(){return new MyBean();}
}
- SportsCar2가 나오는이유는 덮어쓰기 때문
@Import({Config1.class, Config2.class})
class MainConfig{ @Bean Car car() {return new Car();} }
class Config1 { @Bean Car sportsCar() {return new SportsCar();} }
class Config2 { @Bean Car sportsCar() {return new SportsCar2();} }
ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class); // 자바 설정을 이용하는 AC
- 위와 같음
- MainConfig와 Config1 등록
//@Import({Config1.class, Config2.class})
@Import(MyImportSelector.class)
class MainConfig{ @Bean Car car() {return new Car();} }
class Config1 { @Bean Car sportsCar() {return new SportsCar();} }
class Config2 { @Bean Car sportsCar() {return new SportsCar2();} }
class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{Config1.class.getName()};
}
}
- Config1만 나오는 모습...
- 사용자 정의 애너테이션을 이용한 등록
//@Import({Config1.class, Config2.class})
//@Import(MyImportSelector.class)
@EnableMyAutoConfiguration("test")
class MainConfig{ @Bean Car car() {return new Car();} }
class Config1 { @Bean Car sportsCar() {return new SportsCar();} }
class Config2 { @Bean Car sportsCar() {return new SportsCar2();} }
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelector.class)
@interface EnableMyAutoConfiguration {
String value() default "";
}
class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attr = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EnableMyAutoConfiguration.class.getName()));
// String mode = "test";
String mode = attr.getString("value");
if (mode.equals("test"))
return new String[]{Config1.class.getName()};
else
return new String[]{Config2.class.getName()};
}
}
- Config1이 잘나온다
//@Import({Config1.class, Config2.class})
//@Import(MyImportSelector.class)
@EnableMyAutoConfiguration("test2")
class MainConfig{ @Bean Car car() {return new Car();} }
- test를 바꾸면?
- Config2가 잘나온다
'Spring DI, AOP' 카테고리의 다른 글
10. AOP의 원리와 용어 - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |
---|---|
9. 외부 설정 사용하기 - 패스트캠퍼스 백엔드 부트캠프 3기 (2) | 2025.02.24 |
7. 의존성 관리와 설정의 자동화(2) - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |
6. 의존성 관리와 설정의 자동화(1) - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |
5. Spring 애너테이션 - 패스트캠퍼스 백엔드 부트캠프 3기 (0) | 2025.02.24 |