12장. Annotation

4 minute read

목표

자바의 Annotation에 대해 학습하세요. issue

학습할 것

애노테이션

사전적인 의미로는 주석을 의미한다. 하지만 자바에서는 그 주석 의미 이상의 기능으로 동작한다. 특수한 기능을 주입할 수 있는 메타데이터라고 말할 수 있다.

자바 애노테이션의 기능으로 xml과 같은 부가적인 파일이 아닌 자바 파일 내부에서 유효성 검사 및 설정에 대해서 바로 셋업하는 것이 가능해졌다.

추가적으로 원하는 클래스는 주입한다던지 코드를 생성할 수 있게 한다던지 기능도 가능하다.

애노테이션의 종류

Built-in Annotation : 자바에서 기본적으로 제공하는 어노테이션

  • @Override 선언한 메서드가 오버라이드라는 것을 나타냄. 만약 오버라이드 아닌 경우 컴파일 에러가 발생.

  • @Deprecated 해당 메소드를 더 이상 사용안하겠다는 것. 사용 시 컴파일 경고 나옴.

  • @SuppressWarnings 컴파일 경고를 무시하겠다는 것

  • @SafeVarargs 가변인자 매개변수를 사용할 때의 경고를 무시

  • @FunctionalInterface 람다 함수등을 위한 인터페이스 지정. 만약 메소드가 2개인 경우에는 컴파일단에서 에러 발생.

Meta Annotation : 커스텀 어노테이션을 만들수 있게 제공된 어노테이션.

  • @Retention 어노테이션이 유지되는 기간을 지정하는데 사용한다.(세가지 유지정책 사용)

  • @Documented 해당 어노테이션을 javadoc에 포함시킵니다.

  • @Target 어노테이션이 적용할 위치를 지정합니다.

  • @Inherited 어노테이션의 상속을 가능하도록 함.

  • @Repeatable 연속적으로 어노테이션을 사용할 수 있게 해줌

@retention

애노테이션을 유지하는 기간을 지정하는 애노테이션이다. 3가지 정책이 존재한다.

종류

  • RetentionPolicy.Source : 컴파일 전까지만 유효

  • RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효

  • RetentionPolicy.RUNTIME : 컴파일 이후에도 JVM에 의해 계속 참조 가능

위와 같은 정책을 가지고 내가 정의한 애노테이션이 언제까지 사용가능하도록 할지 정하는 것이다. 언제나 적절한 정의는 필요하다. 굳이 런타임에 사용하지도 않는 것을 메모리에 올려놓을 필요없는 것과 같다.

실제로 바이트 코드를 뜯어본 내용을 보면 RUNTIME을 제외한 경우는 실제 바이트 코드 단위에서는 기록에 남지는 않는 것을 볼 수 있다.

@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}
---

@Retention(RetentionPolicy.Source)
public @interface CustomAnnotation {
}

@target

애노테이션이 적용될 위치를 지정하는 애노테이션이다.

종류

  • ElementType.PACKAGE : 패키지선언
  • ElementType.TYPE : 타입선언
  • ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
  • ElementType.CONSRTUCTOR : 생성자 선언
  • ElementType.FIELD : 멤버변수 선언
  • ElementType.LOCAL_VARIABLE : 지역 변수 선언
  • ElementType.METHOD : 메서드 선언
  • ElementType.PARAMETER : 전달인자 선언
  • ElementType.TYPE_PARAMETER : 전달인자 타입 선언
  • ElementType.TYPE_USE : 타입 선언
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSRTUCTOR})
public @interface CustomAnnotation {}

@documented

@Documented는 해당 어노테이션을 javadoc 파일에 추가시킬지 여부이다.

애노테이션 프로세서

컴파일시 애노테이션에 맞는 행동을 할 수 있도록 만드는 자바에서 제공해주는 프로세서

기본적으로 AbstractProcessor라는 추상클래스를 상속받아서 구현해야 함.

동작 순서

  1. 어노테이션 클래스를 생성한다.
  2. 어노테이션을 사용한다.
  3. 컴파일하면, 어노테이션 프로세서(파서)가 어노테이션을 처리한다.

추가적으로 읽으면 좋을 자료

Annotation Processing 101 (번역)

fakeLombok - lee_maru님의 블로그

어떤 프로그래머 저장소 - 정말 깔끔한 블로그

ref

Seung’s님의 블로그

pej4303님의 블로그

라이브 방송

책 추천

방송 중

  • 애노테이션 = 주석
    • 완전히 주석같지는 않지만 주석과 비슷한 류의 장치다
    • 주석이기 때문에 실행되는 코드라고 생각안하는 게 좋다.
    • 애노테이션을 잘 공부하지 않으면 해당 코드가 어떤 것을 실행한다고 생각하는데 단순히 마크를 해놓은 것으로 생각하면 된다.
    • 약간 다이나믹하게 실행되는 코드는 안들어감.
    • 런타임중에 알아내야 하는 값은 못들어감.
    • 컴파일러 수준에서 해석이 되거나 완전히 정적이어야 됨.
    • 런타임중에 바뀌는 것은 있을 수 없다.
  • 주의해야될 것 중 하나 @Retention
    • 언제까지 유지할 것인가. retention policy가 있음.
    • 3개가 존재함.
    • source, class, runtime
    • 이것 3개를 이해하려면 첫시간에 한것을 이해 해야함
    • source -> class -> runtime
    • source: 소스 코드에만 유지하겠다. 컴파일하고 나면 애노페이션이 없어짐. 컴파일 이후에 안쓰겠다. (정말 주석으로만 쓴 것)
      • 예시) @override. 컴파일 할때만 사용하겠다.
    • class: 바이트코드로 남기겠다. 클래스 파일에 남겼다.
      • 이때부터 Reflection이라는 것이 가능해짐. 클래스 정보에 남겨져 있는 것임. 해당 애노테이션. runtime에 해당 클래스 정보를 읽을 수 있게 된 것임.
      • 바이트코드에 들어가 있음.
      • 메모리에 올릴 때 해당 정보를 누락시켜버림.
    • runtime: 메모리 해당 정보를 올리겠다.
      • Reflection - 반사. 반사해서 보는 것.
    • 바이트 코드에서 읽어오는게 빠르냐, 리플렉션이 더 빠르냐.
      • 몰라. 왜냐하면 리플렉션 자체가 부하가 조금 있음. 실제로 성능의 민감한 경우는 직접 재봐야되는지 일단 생각을 해보면
      • 바이트 코드: 클래스 파일을 읽어야됨. 클래스 로딩도 하고. 크기에 따라 달라지겠지.
      • 리플렉션: 메모리에 적재하고. 그 값을 읽어오고 이런 시간이 걸리긴 할 듯
      • 이론적으로는 바이트코드가 더 빠를 것 같음. 경우에 따라 리플렉션이 빠른 경우가 있을 수 있을 듯. 바이트 코드가 크다면
    • 이렇게 나눈 것은 결국 필요한 만큼만 남기도록 하기 위해서 이다.
    • 리플렉션을 쓰면 잘 사용할 수 있기는 하지. 편하지. 하지만 한번 생각해봤을 때 이게 런타임때 까지 쓸 이유가 있는지 생각.
  • 에러 메시지는 무조건 읽어야된다.
    • 스택 트레이스에 엄청난 정보가 들어가 있다.
  • @Documented
    • 문서화를 자동으로 해줌
    • Javadoc
  • @Inherited
    • 하위 클래스에게도 이 애노페이션을 전파하고 싶을 때 사용
    • 내가 상속을 썼다는 것을 알어. 그러면 부모의 애노테이션을 볼 수 있으.
  • getDeclaredAnnotaion() -> @Inherited 된 애노테이션을 무시해버림. 선언되어진 것들만.
  • getDeclaredFields() -> private한 모든 필드까지 가져옴. 거기에 선언되어진 것들. 상속된 놈들 ㄴㄴ. 선언되어진 것들만. private까지 볼 수 있음.
  • getFields() -> 밖에서 볼 수 있는 것들만. 그래서 선언되어져있어도 private이면 못본다. 밖에서 볼 수 있는 것만.

  • 애노페이션. 잘 만들어진 것들. 잘 사용하면 너무 좋다.

  • @Target
    • 어디다가 붙일지 제한을 함.
    • 안붙이면 모든 곳에 붙일 수 있음
  • 애노테이션 프로세서

  • 자바의 ServiceLoader
    • https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html
    • 인터페이스들의 구현체가 여러개가 있는 경우
    • 인터페이스의 구현체가 jar 파일 변경으로만으로 다르게 동작하고 싶은 경우
    • jar파일만 바꿔끼면 동작하게 만들고 싶다.
    • 해당 하는 인터페이스 안에 있는 구현체를 가져올 수 있는 것 => ServiceLoader
    • 제각각에 대한 Loa
    • jar파일 각각 에다가 META-INF/services 라는 것을 만들고 인터페이스 이름 full package이름을 넣는다.
    • 그리고 해당 파일 안에다가 구현체 풀 패키지 경로
    • 직접 참조 하지 않아도 사용가능.
    • 실제 구현체는 몰라. 알아낼 수는 있지만 일단 몰라. 인터페이스만 알어. 그러면 모두 가져올 수 있으!!
    • 해당하는 것과 비슷하게 spring-boot-autoconfiguration 안에 META-INF 안에 spring.factories가 있는데. 이걸 보면서 아 이걸보면 자동으로 설정이 되는구나. 그리고 내가 원하는 커스텀을 적으면 자동으로 적용할 수 있겠구나.
main() {
    ServiceLoader<CodeFactory> loader = ServiceLoad.load(CodeFactory.class);

}
  • 개발자의 소양은 빨리 배우는 것이다. 그러기 위해서는 이전에 아는 것을 이용해서 빨리 배울 수 있는 것이다. 그래서 계속 배워야된다. 계속 공부해야지 빨리배우고 앞으로 나아갈 수 있다.

  • @FunctionalInterface: 구현 함수가 하나인 경우. 거기에 이 애노페이션을 붙이면 함수형 인터페이스로 사용할 수 있도록 만들어줌

  • value라는 값이 존재함. annotaion에.
    • 이름안주고 사용할 수 있게 도와준다.
  • 실제 롬복같은 것을 만들어준 사람이 있음. 정말로 개발자같은 마인드를 가지신 것 같다.
    • https://github.com/lee-maru/fakeLombok

베스트 글 모음

https://velog.io/@ljs0429777/12%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C-%EC%95%A0%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98

https://velog.io/@kwj1270/%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98

https://catch-me-java.tistory.com/49

https://b-programmer.tistory.com/264

https://gowoonsori.site/java/annotation/

https://blog.naver.com/hsm622/222226824623

https://www.notion.so/12-386f4cd47d37448fa0252d3ed22b45b7#daf688bdb061428d80fde6fc17215e1c

Leave a comment