스프링을 이용해 개발을 하다보면 어노테이션을 자주 마주하게 된다.
따라서, 어노테이션이 무엇이고, 어노테이션이 어떻게 리플렉션으로 동작하는지, 그리고 리플렉션이 무엇인지 알아보고자 한다.
어노테이션 (Annotation)
코드에 추가할 수 있는 메타데이터의 한 형태로, @(at) 문자를 통해 표현할 수 있다.
어노테이션은 코드에 부가적인 정보를 제공하는 데 사용되는 표현 방법이다.
어노테이션은 소스 코드에 주석 형태로 추가되어 컴파일러, 런타임 환경 또는 다른 프로세스에게 특별한 정보를 전달한다.
대표적인 어노테이션
- @Override : 해당 어노테이션이 선언되어 있는 메서드는 오버라이드됨을 컴파일러에게 알려줌
- @Deprecated : 해당 메서드는 더 이상 사용되지 않는다는 것을 컴파일러에게 알려줌 + 경고
- @Supress Warnings : 경고를 무시한다고 컴파일러에게 알려줌. (사용 시 주석으로 이유를 설명할 것)
메타 어노테이션
메타 어노테이션은 어노테이션을 선언하기 위해 사용하는 어노테이션이다.
- @Target : 어노테이션이 적용되는 대상을 지정 (지정하지 않은 곳에 설정한다면 컴파일 에러가 발생)
- ElementType.CONSTRUCTOR : 생성자
- ElementType.FIELD : 필드
- ElementType.LOCAL_VARIABLE : 로컬 변수
- ElementType.METHOD : 메소드
- ElementType.PACKAGE : 패키지
- ElementType.PARAMETER : 파라미터
- ElementType.TYPE : 클래스, 인터페이스, 열거 타임
- @Retention : 어노테이션의 생명 주기를 선언 (언제까지 유지할 것인가?)
- RetentionPolicy.SOURCE: source에서만 유지한다. 어노테이션 정보가 컴파일시 사라며, 바이트 코드에서는 존재하지 않는다. 코드를 분석할 때만 의미가 존재한다.
- RetentionPolicy.CLASS: class 파일 까지(바이트 코드까지)는 정보가 유지된다. 런타임 때는 사라진다.
- RetentionPolicy.RUNTIME: 런타임까지 정보 유지한다. 런타임시에도 어노테이션 정보를 얻을 수 있기 때문에, 리플렉션을 이용해 정보를 얻을 수 있다.
- @Document : 해당 어노테이션에 대한 정보가 javadocs 문서에 포함됨을 선언
- @Inherited : 모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능함을 선언 (어노테이션을 적용한 슈퍼 클래스를 상속한 서브 클래스도 어노테이션의 영향을 받게 된다.)
- @Interface : 어노테이션을 선언할 때 사용
- @Repeatable : 어노테이션을 반복적으로 선언할 때 사용
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Override는 위와 같이 선언되어 있다고 한다.
그렇다면.. 어노테이션을 왜 사용할까?
어노테이션의 필요성
어노테이션은 주로 코드의 가독성을 높이고 유지보수를 용이하게 하는 데 사용된다. 따라서 개발자들은 더 효율적이고 명확한 코드를 작성할 수 있게 된다고 한다.
하지만, 어노테이션은 코드에 메타데이터를 추가하는 역할만 하지, 메타데이터를 실제로 읽고 처리하기 위해서는 리플렉션이 필요하다.
그럼 이제 리플렉션이 무엇인지 알아보자.
리플렉션(Reflection)
Java 리플렉션은 객체를 통해 클래스의 정보를 분석하여 런타임에 클래스의 동작을 검사하거나 조작하는 프로그램 기법이다.
클래스 파일의 위치나 이름만 있다면 해당 클래스의 정보를 얻어내고, 객체를 생성하는 것 또한 가능하게 해주어 유연한 프로그래밍을 가능하게 해준다.
+) 왜 리플렉션이 필요한가?
- 런타임 정보 접근 : 어노테이션은 컴파일 타임에 코드에 부착되지만, 그 정보를 프로그램 실행 중에 활용하려면 런타임에 해당 어노테이션을 가진 클래스나 메서드 등을 찾아야 한다.
- 동적 처리 : 어떤 클래스나 메서드에 어떤 어노테이션이 붙어있는지는 컴파일 시점에 알 수 없을 수 있다. 리플렉션을 사용하면 런타임에 이 정보를 동적으로 확인하고 처리할 수 있다.
리플렉션은 애플리케이션 개발에서보다는 프레임워크, 라이브러리에서 많이 사용된다.
- 프레임워크나 라이브러리가 사용자가 어떤 클래스나 멤버를 정의할 지 미리 알 수 없기 때문이다.
- 사용자 정의 클래스와 기존의 프레임워크 기능을 동적으로 연결하기 위해 리플렉션을 사용한다.
사용 예시
- 스프링의 의존성 주입(Dependency Injection) : @Autowired 어노테이션이 붙은 필드나 메서드를 리플렉션으로 찾아서 의존성을 주입한다.
- 프레임 워크 활용 : @Controller, @Service, @Repository 등의 어노테이션이 붙은 클래스를 리플렉션으로 스캔하여 적절한 bean으로 등록한다.
- Entity 매핑: JPA에서는 @Entity, @Table, @Column 등의 어노테이션 정보를 리플렉션으로 읽어와 데이터베이스 테이블과 객체를 매핑한다.
- Spring, Hibernate, Lombok 등 많은 프레임워크와 라이브러리에서 리플렉션을 적극적으로 활용하고 있다.
리플렉션을 이용하면 클래스와 메서드의 메타정보를 사용해서 애플리케이션을 동적으로 유연하게 만들 수 있다. 하지만 리플렉션 기술은 런타임에 동작하기 때문에, 컴파일 시점에 오류를 잡을 수 없다는 단점이 존재한다고 한다.
참고 1
참고 2
참고 3
참고 4
'개발 > Java' 카테고리의 다른 글
자바 기본 - System.out.println() (0) | 2024.11.07 |
---|---|
자바 기본 - 람다와 스트림 (0) | 2024.11.07 |
자바 기본 - 제네릭 (0) | 2024.11.06 |
자바 기본 - 예외 (2) | 2024.11.06 |
자바 기본 - 문자열 (0) | 2024.11.05 |