Topic (오늘의 주제)
자바 리플렉션(Java Reflection)의 개념과 동작 원리
구체적인 클래스 타입을 알지 못해도 런타임에 클래스의 정보에 접근하고 동적으로 객체를 다루는 방법을 학습하며, Spring과 JPA 같은 프레임워크가 내부적으로 어떻게 동작하는지 이해합니다.
Why (왜 사용하는가? 왜 중요한가?)
- 실무: 프레임워크나 공통 라이브러리(Spring, Hibernate, Jackson 등)가 개발자가 작성한 임의의 클래스를 런타임에 동적으로 읽어 객체를 생성하고 의존성을 주입(DI)하기 위해 반드시 필요합니다. 리플렉션이 없다면 모든 프레임워크 로직을 하드코딩해야 합니다.
- 구조적 의미: 컴파일 타임이 아닌 런타임(Runtime)에 클래스의 메타데이터를 분석하고 조작할 수 있는 극강의 유연성을 제공합니다. 정적인 자바 언어에 동적인 성격을 부여하는 핵심 기술입니다.
- 면접 의도: 지원자가 프레임워크의 동작 원리(예: IoC 컨테이너가 Spring Bean을 생성하는 방식)를 깊이 있게 이해하고 있는지, 그리고 유연성 이면에 숨겨진 성능 저하와 캡슐화 파괴라는 '리플렉션의 양날의 검'을 인지하고 있는지 확인하려 합니다.
Core Concept (핵심 개념 정리)
| 요소 | 내용 |
| 개념 정의 | 자바 런타임 환경에서 구체적인 클래스 타입을 몰라도 해당 클래스의 메타데이터(메서드, 타입, 변수 등)에 접근하고 객체를 조작할 수 있도록 지원하는 자바 API(java.lang.reflect)입니다. |
| 동작 방식 | JVM은 클래스 로더를 통해 클래스를 읽어들여 메모리(Method Area)에 보관하고, 이를 기반으로 Class 객체를 생성합니다. 리플렉션은 이 Class 객체를 가져와(Class.forName() 등) 런타임에 생성자 호출, 메서드 실행(invoke()), 필드 값 변경을 수행합니다. |
| 장점/단점 | 장점: 런타임에 코드를 동적으로 조립할 수 있어 프레임워크와 같은 범용적인 코드 작성이 가능합니다. 단점: 1. 컴파일 타임의 타입 안정성(Type Safety)을 잃습니다. 2. setAccessible(true)를 통해 private 멤버에 접근할 수 있어 객체지향의 캡슐화를 파괴합니다. 3. 동적으로 해석되므로 일반적인 메서드 호출보다 성능이 느립니다. |
| 필요 조건 | JVM에 의해 클래스가 메모리에 로드되어 있어야 하며, 접근하고자 하는 대상의 Class 객체 참조가 필요합니다. |
| 예시/비교 | 정적 바인딩 vs 동적 바인딩: 일반적인 new 키워드를 통한 객체 생성은 컴파일 타임에 타입이 결정(정적 바인딩)되지만, 리플렉션은 실행 중인 런타임에 동적으로 객체를 생성하고 메서드를 매핑(동적 바인딩)합니다. |
Interview Answer Version (면접 답변식 요약)
"자바 리플렉션은 런타임에 클래스의 메타데이터를 분석하여 동적으로 객체를 생성하거나 메서드를 호출할 수 있게 해주는 API입니다.
우리가 흔히 사용하는 Spring의 의존성 주입(DI)이나 JPA의 엔티티 매핑, Jackson 라이브러리의 JSON 변환 모두 내부적으로 이 리플렉션을 사용하여 개발자가 작성한 클래스를 동적으로 처리합니다.
하지만 컴파일 시점의 타입 검사를 우회하고, private 필드에 접근하여 캡슐화를 깰 수 있으며, 성능 오버헤드가 발생한다는 단점이 있습니다. 따라서 일반적인 비즈니스 로직 개발보다는 프레임워크나 공통 유틸리티 라이브러리를 구축할 때 제한적으로 사용하는 것이 바람직합니다."
Practical Tip (사용시 주의할 점 or 활용 예)
- 실무 활용 예: * Spring IoC 컨테이너: @Component나 @Service가 붙은 클래스를 찾아 리플렉션으로 객체(Spring Bean)를 인스턴스화하고, @Autowired가 붙은 필드나 생성자에 의존성을 주입합니다.
- 동적 프록시 (AOP): 이전 주제였던 Spring AOP에서 Proxy 객체를 런타임에 찍어낼 때도 내부적으로 리플렉션 기술이 사용됩니다.
- 설정 시 반드시 고려해야 할 파라미터/문법:
- Field.setAccessible(true): 접근 제어자(private, protected)를 무시하고 필드나 메서드에 접근할 수 있게 해줍니다. 이 때문에 보안 매니저 설정에 따라 런타임 에러(SecurityException)가 발생할 수 있습니다.
- "이걸 모르고 사용하면 생기는 문제" (기본 생성자 부재로 인한 에러):
- JPA Entity 클래스나 Spring 컨트롤러의 Request DTO를 만들 때 **기본 생성자(No/Default Arguments Constructor)**를 깜빡하면 런타임 에러가 발생합니다. 이는 JPA나 Spring(Jackson)이 파라미터가 있는 생성자의 정보는 런타임에 매핑하기 까다롭기 때문에, 먼저 리플렉션을 통해 '기본 생성자'로 빈 객체를 만든 후, 리플렉션의 필드 주입 기능을 사용해 내부 값을 채워 넣는 방식을 사용하기 때문입니다. 리플렉션의 원리를 모르면 왜 자꾸 기본 생성자를 강제하는지 이해하기 어렵습니다.
예상 꼬리질문 정리
- JPA Entity나 Spring DTO에 기본 생성자(Default Constructor)가 반드시 필요한 이유는 무엇인가요? 자바 리플렉션의 동작 방식과 연관 지어 설명해 주세요.
- (의도: 프레임워크가 객체를 생성할 때 왜 기본 생성자를 찾는지, 리플렉션의 인스턴스화 과정을 명확히 이해하고 있는지 확인)
- 리플렉션은 왜 일반적인 객체 생성(new)이나 메서드 호출보다 성능이 느린가요? 이를 극복하기 위해 프레임워크들은 내부적으로 어떤 최적화를 수행하나요?
- (의도: JIT 컴파일러의 최적화 한계 등 JVM 레벨의 동작 방식을 이해하고 있는지, 그리고 메타데이터 캐싱 전략에 대해 알고 있는지 확인)
- Spring Framework에서 의존성을 주입(DI)할 때, 생성자 주입을 권장하지만 필드 주입(@Autowired in field)도 가능합니다. 필드 주입은 내부적으로 어떻게 작동하며, 왜 캡슐화를 파괴한다고 평가받나요?
- (의도: 리플렉션의 setAccessible(true)를 활용한 필드 주입 원리를 이해하고, 이로 인해 발생하는 테스트의 어려움과 OOP 관점의 단점을 아는지 확인)
'Archive > Daily Dev Q&A' 카테고리의 다른 글
| Daily Dev Q&A: 동기와 비동기 (0) | 2026.02.24 |
|---|---|
| Daily Dev Q&A: Redis의 특징 (0) | 2026.02.24 |
| Daily Dev Q&A: Spring AOP (0) | 2026.02.23 |
| Daily Dev Q&A: 트랜잭션 격리 수준 (0) | 2026.02.02 |
| Daily Dev Q&A: 데이터베이스 락 (0) | 2026.02.02 |