Annotation

WebStudy/Spring / / 2021. 7. 21. 23:11

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

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을 자동으로 주입
      • 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 "";
}
  • 위 어노테이션 사용하는 클래스
    • someValue 값을 입력하면서 Aconfig를 호출하도록 함
@Configuration
@EnableAutoMyModule("someValue")
public class MainConfig {
    @Bean
    public UseMyBean useMyBean() {
        return new UseMyBean();
    }
}
  • 실행
public class ImportSelectApp {
    public static void main(String ar[]) {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfig.class);
        UseMyBean bean = context.getBean(UseMyBean.class);
        bean.printMsg();
    }
}
  • 위 어노테이션 사용하는 클래스
    • someValue 값을 입력하면서 Aconfig를 호출하도록 함
      @Configuration
      @EnableAutoMyModule("someValue")
      public class MainConfig {
      @Bean
      public UseMyBean useMyBean() {
        return new UseMyBean();
      }
      }
  • 실행
    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");
        }
      }
  • 환경변수를 읽고 판별하는 클래스
    • 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"));
        }
      }
  • 위를 이용하는 클래스
    • 각각의 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

'WebStudy > Spring' 카테고리의 다른 글

예외 처리 및 테스트  (0) 2021.07.24
Boot Starter  (0) 2021.07.22
REST API 2  (0) 2021.07.20
REST API 1  (0) 2021.07.19
정적 자원 관리와 템플릿 엔진  (0) 2021.07.17
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기