이번 글에서는
프레임워크
,라이브러리
에서 많이 사용되는 리플렉션을 정리해 보려고 합니다.
반사된 물체를 통해서 행동하는 것을 리플렉션
이라고 합니다.
Java
에서는 실제 물체가 Class이고,
반사된 물체는 JVM 메모리 영역 저장된 Class 정보입니다.
리플렉션은 JVM 메모리 영역에 저장된 Class 정보를 꺼내와서 필드, 생성자, 메서드 등을 가져와 사용하는 기능입니다.
Class
는 실행 중인 자바 어플리케이션의 클래스와 인터페이스의 정보를 가진 클래스입니다.
Class
는 JVM에 의해 자동으로 생성됩니다.
Class<?> clazz = User.class;
Class<?> clazz = user.getClass();
Class<?> clazz = Class.forName("{경로를 포함한 클래스 이름}");
3가지 방법으로 Class를 불러올 수 있습니다.
Class에는 getFields()
, getMethods()
, getAnnotations()
, getDeclaredFields()
, getDeclaredMethods()
, getDeclaredAnnotations()
등의 메서드가 선언되어있습니다.
getXXX()
는 상속한 메서드를 포함하여 public인 메서드만 불러옵니다.
getDelcaredXXX()
는 직접 클래스에 선언한 메서드만 불러옵니다.
접근제한자가 public이 아닌 경우 setAccessible(true)
를 사용하면 접근할 수 있습니다.
프레임워크나 라이브러리에서 많이 사용합니다.
ex) Spring
, JPA
, Jackson
, Mockito
, Junit
, Intellij 자동완성 기능
...
프레임워크나 라이브러리는 사용자가 생성한 객체가 어떤 타입인지 컴파일 시점까지 알 수 없습니다. 이러한 문제를 해결하기 위해 리플렉션을 사용합니다.
많은 프레임워크나 라이브러리에서 객체의 기본생성자를 필요로 합니다.
ex) JPA
, Jackson
...
객체를 생성하는 방법 중 기본생성자로 객체를 생성하고,
필드를 통해 값을 넣는게 가장 간단한 방법이기 때문입니다.
일반 메서드 호출보다 성능이 훨씬 떨어집니다.
리플렉션 API는 컴파일 시점이 아니라 런타임 시점에 클래스를 분석하는데
JVM을 최적화할 수 없기 때문에 성능 저하가 발생하게 됩니다.
런타임 시점에 클래스 정보를 알 수 있기 때문에
컴파일 시점에 오류를 확인할 수 없습니다.
setAccessible(true)
를 통해 접근할 수 없는 필드나 메서드의 정보를 알 수 있고,
필드 값을 변경할 수 있습니다.
Entity
, DTO
에서 리플렉션을 사용하기 때문에 기본 생성자가 필요하다는 것을 알게 되었습니다.
나중에 리플렉션을 통해 간단한 프레임워크나 라이브러리를 만들어 보면 좋을 것 같습니다.