Annotation
zl존석동
·2022. 2. 20. 19:48
어노테이션이란?
어노테이션(Annotation)은 코드에 메타데이터를 추가하는 방법이다.
어노테이션은 @ 기호로 시작하며, 컴파일러나 런타임 시점에 정보를 제공하는데 사용된다.
언제쓸까?
컴파일 시점 체킹
어노테이션을 사용하여 코드를 컴파일할 때 에러를 검출하는 기능을 추가할 수 있다
런타임 처리
어노테이션을 사용하여 런타임에 동작을 변경하는 기능을 추가할 수 있다
문서
어노테이션을 사용하여 문서를 생성하는 기능을 추가할 수 있다.
자바 표준 어노테이션
@Override
선언한 메소드가 상속받은 것임을 나타낸다.
@SuppressWarnings
선언한 곳의 컴파일 경고를 무시한다.
@Deprecated
선언한 곳이 더이상 사용되지 않는 부분임을 선언하며 사용하면 컴파일 시 경고를 해준다.
@FunctionalInterface
java8에서 나온 것으로 함수형 인터페이스임을 지정해주는 어노테이션이다.
따라서 default 메소드를 제외한 하나의 유일한 메소드가 반드시 있어야 한다.
어노테이션을 위한 어노테이션
@Retention
자바 컴파일러가 어노테이션을 다루게 하는 방법을 선언해주는 것이다.
생명주기와 관련있다.
- RetentionPolicy.SOURCE : 컴파일 전까지 유효.
- RetentionPolicy.CLASS : 컴파일러가 클래스를 참조할 때까지 유효.
- RetentionPolicy.RUNTIME : 런타임 중에도 참조 가능(리플렉션)
@Inherited
어노테이션을 상속 가능하게 해준다.
@Documented
javadoc에 포함시킨다.
@Target
어노테이션을 선언할 위치를 선언해준다.
- ElementType.PACKAGE : 패키지 선언
- ElementType.TYPE : 타입 선언
- ElementType.ANNOTATION_TYPE : 어노테이션 타입 선언
- ElementType.CONSTRUCTOR : 생성자 선언
- ElementType.FIELD : 멤버 변수 선언
- ElementType.LOCAL_VARIABLE : 지역 변수 선언
- ElementType.METHOD : 메서드 선언
- ElementType.PARAMETER : 전달인자 선언
사용예시
DI를 구현해보자
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}
클래스의 멤버에 사용해야 하니 FIELD 타겟을 선언했다.
런타임 시점에 찾아서 주입해야 되니 RUNTIME으로 생명주기를 선언했다.
public class AutowiredAnnotationProcessor {
public static void process(Object object) throws IllegalAccessException {
Class<?> clazz = object.getClass();
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Class<?> fieldClass = field.getType();
Object fieldValue = findBean(fieldClass);
field.set(object, fieldValue);
}
}
}
// 필드 타입에 해당하는 구현체를 찾는 메소드
private static Object findBean(Class<?> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new Exception("Failed to instantiate class " + clazz.getName() + ": " + e.getMessage());
}
}
}
DI를 실제로 처리할 수행 클래스를 작성한다.
@Autowired 가 붙은 필드의 타입을 가져와 찾아 초기화 한 다음 해당 필드에 넣어준다.
물론 이 경우 인터페이스 필드에 대해 사용된다면 대응할 수 없고
여러 곳에서 주입되는 경우 새로운 인스턴스를 계속해서 가져오는 형태겠지만 싱글턴 패턴을 사용해서 한 번만 초기화 하고 두번째 부터는 같은 인스턴스를 반환하게 해줄 수 있다.
public class Person {
@Autowired
private SomeService someService;
public void say() {
System.out.println(someService.getSomething());
}
}
public static void main(String[] args) throws IllegalAccessException {
Person person = new Person();
AutowiredAnnotationProcessor.process(person);
person.say();
}
'Java' 카테고리의 다른 글
[MyBatis] INSERT 성공 후 생성된 자원의 PK 같이 얻어오기 (0) | 2022.02.26 |
---|---|
[java] Reflection (0) | 2022.02.14 |
[Java] ConcurrentModificationException 해결하기 (0) | 2022.02.04 |
[Java] 올바른 Map Iteration (0) | 2022.01.23 |
[Java] 예외란 뭘까 (0) | 2022.01.10 |