리플렉션은 객체의 구체적인 타입을 알지 못해도 해당 객체의 멤버변수, 메서드 등에 접근할 수 있도록 해주는 기능입니다.
자바 어플리케이션이 컴파일되고 실행될 때, 클래스 로더는 자바 바이트코드(.class)를 읽어서 메모리에 저장합니다. 특히, Class<T> 타입의 인스턴스를 만들어주는데요, 항상 있다는 것을 보장할 수 있기 때문에 아래와 같이 클래스를 만들기만 하면 바로 사용할 수 있습니다.
class Member (
val name: String,
)
val memberClass = Member::class.java
val memberClass2 = Member("chobo").class
이러한 Class<T> 인스턴스는 해당 클래스에 정의된 멤버변수, 메서드, 생성자 등 클래스의 모든 정보에 접근할 수 있습니다.
이처럼 리플렉션은 런타임 시점에 정해지지 않은 인스턴스를 조작할 수 있는 유연성을 제공해주지만 주의하여 사용해야 합니다.
성능 이슈
컴파일 이후에 생성된 바이트코드는 JVM 의 인터프리터를 통해 한 줄 씩 기계어로 번역되어 실행되는데요, 여기서 발생하는 성능 이슈를 해결하기 위해 여러 방식을 도입했습니다. 그 중, JIT(Just-In-Time) 컴파일러의 캐싱을 통해 한 번 기계어로 번역된 메서드가 다시 실행되면 다시 번역하지 않고 이전에 번역한 것을 사용할 수 있게 하는 방식으로 최적화합니다.
자바의 컴파일된 결과물은 특정 머신에 종속되지 않기 위해 바이너리 코드를 생성하지 않고 JVM 이 실행할 수 있는 바이트 코드를 생성합니다.
하지만 리플렉션은 클래스의 바이트 코드를 이용하는 것이 아닌, 메모리에 해당 클래스의 특성을 투영한 데이터를 이용하므로 매 번 호출되는 메서드라도 최적화가 되지 않게 됩니다.
이외에도 Typeless 로 인한 추적이 불가하여 리팩토링에 어려움, Private 필드 접근 가능함으로 인해 캡슐화 깨짐 등 여러가지 문제가 있으므로, 프로덕션 코드에서 사용하는 것은 지양하는 것이 좋아 보입니다.
참고로 클래스 로더는 기본적으로 실행에 필요한 .class 만 메모리에 올려 실행하고, 나머지는 필요할 때 로딩하는 Lazy loading 전략을 따릅니다. 따라서, 성능 테스트 혹은 배포 시에 초기 warm up 을 하면 좋을 수 있습니다.
'Spring' 카테고리의 다른 글
Kubernetes 에서 안전하게 힙 덤프 수행하기 (0) | 2024.06.13 |
---|---|
Github Rest API 를 통한 테스트 자동화 (0) | 2024.03.31 |
Jpa Multi-datasource 구성과 @Transactional (0) | 2024.03.19 |
멀티 스레드 환경에서의 동시성 이슈와 Blocking, Non-blocking 알고리즘을 이용한 동기화 (0) | 2023.12.19 |
Speing Webflux 이해하기 (0) | 2023.08.22 |