Annotation
- annotation
- 자바 1.5 버전부터 지원되는 일종의 metadata
- 컴파일 또는 런타임시에 해석됨
어노테이션 만들기
기본 형식
@Target(ElementType.MTHOD)
@Retention(RetentionPolicy.RUNTIME)
Public @interface Annotation1{}
-
@Target
- 어노테이션이 적용되는 대상을 의미
- ElementType의 요소 중 선택해서 지정
-
@Retention
- 어노테이션이 적용될 범위를 결정
- class
- 어노테이션 작성 시 기본값으로 크래스 파일에 포함, JVM이 로드 X
- runtime
- 클래스 파일에 포함, JVM이 로드해서 리플렉션 API로 참조 가능
- sourcre
- 컴파일 때만 사용, 클래스 파일에 포함 X
- class
- 어노테이션이 적용될 범위를 결정
MyAnnotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String strValue();
int intValue();
}
위를 사용하는 클래스
public class MyService {
@MyAnnotation(strValue = "hi", intValue = 0607)
public void printSomething() {
System.out.println("test my annotation");
}
}
리플렉션 API로 위 메서드에 선언한 MyAnnotation값 확인
리플렉션이란 객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법
public class AnnotationApp {
public static void main(String ar[]) throws Exception {
Method[] methods = Class.forName(MyService.class.getName()).getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation an = methods[i].getAnnotation(MyAnnotation.class);
System.out.println("my annotation str value::" + an.strValue());
System.out.println("my annotation int value:" + an.intValue());
}
}
}
}
스프링 부트 어노테이션
- 부트에서 내부적으로 사용되는 어노테이션들
ImportSelector
-
ImportSelector
interface- 스프링 부트에는 자바로 작성된 많은 설정 클래스들이 어노테이션의 값에 따라 로딩 여부가 결정이 된다.
- 이 때 사용하는 인터페이셔
- 스프링 부트에는 자바로 작성된 많은 설정 클래스들이 어노테이션의 값에 따라 로딩 여부가 결정이 된다.
- 확인을 위한 일반 클래스
public class MyBean { private String msg; public MyBean(String msg) { this.msg = msg; } public String getMsg() { return msg; } }
- 위 클래스를 이용하는 클래스
-
@Autowired
를 통해 MyBean 클래스에 의존성을 주입-
@Autowired
: 각 상황의 타입에 맞는 IoC 컨테이너 안에 존재하는 Bean을 자동으로 주입 ```java public class UseMyBean { @Autowired private MyBean myBean;
-
public void printMsg() { System.out.println(myBean.getMsg()); } } ```
-
- MyBean 등록
- 이후 ImportSelecotr 확인을 위해 두 개의 Bean을 등록한다.
- A
@Configuration public class AConfig { @Bean MyBean myBean() { return new MyBean("from Aconfig"); } }
- B
@Configuration public class BConfig { @Bean MyBean myBean() { return new MyBean("from Bconfig"); } }
- MyImportSelector 클래스
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { AnnotationAttributes attr = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableAutoMyModule.class.getName(), false)); String value = attr.getString("value"); if ("someValue".equals(value)) { return new String[]{AConfig.class.getName()}; } else { return new String[]{BConfig.class.getName()}; } } }
-
@EnableAutoMyModule
만들기- 이를 이용할 클래스에서 MyImportSelector의 메서드를 사용할 수 있도록 Import 함
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Import(MyImportSelector.class) public @interface EnableAutoMyModule { String value() default ""; }
- 이를 이용할 클래스에서 MyImportSelector의 메서드를 사용할 수 있도록 Import 함
- 위 어노테이션 사용하는 클래스
- someValue 값을 입력하면서 Aconfig를 호출하도록 함
@Configuration @EnableAutoMyModule("someValue") public class MainConfig { @Bean public UseMyBean useMyBean() { return new UseMyBean(); } }
- someValue 값을 입력하면서 Aconfig를 호출하도록 함
- 실행
public class ImportSelectApp { public static void main(String ar[]) { ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); UseMyBean bean = context.getBean(UseMyBean.class); bean.printMsg(); } }
@Conditional
-
@Conditional
- 조건에 따라 자바 설정 클래스를 선택할 수 있게 해주는 어노테이션
- Condition 인터페이스를 상속받은 클래스들과 같이 사용하는 어노테이션
- Condition 어노테이션은 프로파일과 유사하지만 더욱 개발에 가깝게 사용할 수 있는 요소
- 프로파일링
- 서비스 혹은 어플리케이션이 ‘실용적인지 여부’를 판단하는 기준
- 프로파일링
- MsgBean 클래스
- interface: 같은 메서드를 가지고 프로퍼티에 따라 다른 클래스가 실행하기 위함
public interface MsgBean { default void printMsg(){ System.out.println("My Bean default is running"); } }
- interface: 같은 메서드를 가지고 프로퍼티에 따라 다른 클래스가 실행하기 위함
- 환경변수를 읽고 판별하는 클래스
- A
public class SiteAConfigCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return "sitea".equals(context.getEnvironment().getProperty("env", "sitea")); } }
- B
public class SiteBConfigCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return "siteb".equals(context.getEnvironment().getProperty("env", "siteb")); } }
- A
- 위를 이용하는 클래스
- 각각의 StieA/BConfigCondition의 matches 메서드 반환값이 true이면 동작할 수 있다.
- A
@Component @Conditional(SiteAConfigCondition.class) public class SiteABean implements MsgBean{ @Override public void printMsg() { System.out.printf("Site A is working"); } }
- B
@Component @Conditional(SiteBConfigCondition.class) public class SiteBBean implements MsgBean{ @Override public void printMsg() { System.out.printf("Site B is working"); } }
- MsgBean과 같은 타입의 클래스가 Bean으로 등록될 수 있도록 설정
@Configuration public class ConditionalMainConfig { @Autowired MsgBean msgBean; }
- MsgBean에서 메시지 출력 클래스
public class ConditionApp { public static void main(String ar[]) { Package pack = ConditionApp.class.getPackage(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan(pack.getName()); context.refresh(); MsgBean bean = context.getBean(MsgBean.class); bean.printMsg(); } }
@AutoConfigurationPackage
-
@AutoConfigurationPackage
- 스프링 부트로 만든 어플리케이션 내에서
- 이 어노테이션이 선언된 패키지 경로를 스프링 콘텍스트가 스캔 가능하도록 하는 역할
- pass
@AutoConfigurationProperties
-
@AutoConfigurationProperties
- 프로퍼티와 매핑된 클래스를 사용할 때
@Bean
대신 사용할 수 있는 어노테이션 -
@Configuration
이나@Component
와 같은 어노테이션들이 클르새 내부에 선언되어 있지 않아서- 빈으로 등록할 수 없는 경우에 사용 할 수 있음
- 프로퍼티와 매핑된 클래스를 사용할 때
- 프로퍼티 그룹화에 사용
- pass