애너테이션(annotation)은 자바에서 소스 코드에 부가적인 정보를 추가하는 메타데이터 역할을 하는데요, 주석과는 달리 컴파일 이후에도 특정 애너테이션은 그대로 유지되어 런타임에서 활용될 수 있습니다.
자바 애너테이션은 크게 세 가지로 나뉩니다.
- SOURCE: 컴파일러에게만 정보를 제공하고 컴파일된 후에는 사라지는 애너테이션입니다. 예를 들어,
@Override
는 컴파일 시에만 필요한 애너테이션이라 컴파일 후에는 제거됩니다. - CLASS: 컴파일된 후 .class 파일에 저장되지만, 런타임에서는 사용되지 않는 애너테이션입니다.
- RUNTIME: 런타임 시에도 유지되어 리플렉션(reflection)을 통해 접근할 수 있는 애너테이션입니다. 예를 들어, Spring 프레임워크의 애너테이션(
@Autowired
,@Service
등)은 런타임 시 사용되기 때문에RUNTIME
으로 설정되어 있습니다. 이들은 런타임에 리플렉션을 통해 접근이 가능하여 프레임워크나 라이브러리에서 자동으로 객체를 주입하거나 설정할 때 활용됩니다.
이렇게 런타임에 유지되는 애너테이션은 자바 리플렉션 API를 통해 동적으로 읽고 처리할 수 있어서, 프레임워크나 라이브러리에서는 코드의 동작을 제어하거나 설정하는 데 자주 사용합니다.
리플렉션(Reflection) API는 자바에서 실행 중인 프로그램이 자신의 구조를 조사하고 수정할 수 있게 하는 강력한 기능입니다. 리플렉션을 통해 클래스의 메서드, 필드, 생성자 등에 대한 정보를 얻고 동적으로 접근할 수 있습니다. 예를 들어, 리플렉션을 통해 클래스 이름을 알지 못하는 상태에서 특정 클래스의 메서드를 호출하거나 필드 값을 읽고 쓸 수 있습니다. 이는 런타임에 동적으로 객체를 생성하거나, 메서드를 호출하는 데 유용합니다.
리플렉션 API의 주요 클래스와 기능은 다음과 같습니다.
자바의 모든 클래스는 Class
클래스의 인스턴스를 통해 그 정보를 참조할 수 있습니다. Class
객체를 통해 메서드, 필드, 생성자 등 다양한 정보를 얻을 수 있습니다. 예를 들어, SomeClass.class
또는 Class.forName("패키지.클래스이름")
을 통해 Class
객체를 가져올 수 있습니다.
Class
객체를 통해 사용할 수 있는 주요 메서드는 다음과 같습니다.
- getMethods() / getDeclaredMethods(): 클래스의 모든 메서드(또는 선언된 메서드)를 가져옵니다.
- getFields() / getDeclaredFields(): 클래스의 모든 필드(또는 선언된 필드)를 가져옵니다.
- getConstructors(): 클래스의 생성자 정보를 가져옵니다.
- getAnnotations(): 클래스에 적용된 애너테이션을 가져옵니다.
리플렉션을 통해 동적으로 객체를 생성하고, 메서드를 호출할 수 있습니다.
- newInstance(): 리플렉션을 통해 동적으로 객체를 생성합니다.
- invoke(): 리플렉션을 사용하여 메서드를 호출합니다.
다음은 간단한 리플렉션 사용 예제입니다.
import java.lang.reflect.Method;
public class ReflectionExample {
public static void main(String[] args) {
try {
// Class 객체를 얻음
Class<?> clazz = Class.forName("mypackage.MyClass");
// 인스턴스 생성
Object obj = clazz.getDeclaredConstructor().newInstance();
// 메서드 호출
Method method = clazz.getMethod("myMethod", String.class);
method.invoke(obj, "Hello, Reflection!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
이 예제에서는 MyClass
클래스의 myMethod
메서드를 런타임에 동적으로 호출합니다. 리플렉션 API를 사용하면 이처럼 컴파일 시점에 클래스나 메서드에 대한 정보를 알지 못해도 런타임에 이를 찾아내고 사용할 수 있습니다.
장점:
- 유연하고 동적인 코드 작성이 가능함.
- 런타임에 클래스 구조를 조사하고 활용할 수 있어 프레임워크나 라이브러리 설계에 필수적임.
단점:
- 성능이 저하될 수 있음.
- 캡슐화를 위반할 수 있어 잘못 사용할 경우 보안 취약점이 생길 수 있음.
리플렉션은 강력하지만 복잡도와 성능 저하가 수반될 수 있어 필요한 경우에 신중하게 사용하는 것이 좋습니다.