https://github.com/ksngh/spring_practice
GitHub - ksngh/spring_practice
Contribute to ksngh/spring_practice development by creating an account on GitHub.
github.com
위 링크에 실습으로 작성한 코드가 들어있습니다.
STEP 1 - POJO 기반 준비 레이어
STEP 1의 목적은 Spring Core를 배우기 전에 왜 이런 Core 레이어가 필요한 지를 직접 경험해보는 데 있었습니다.
이 단계에서는 Spring을 사용하지 않고 순수 Java(POJO + reflection)만으로 객체를 자동으로 생성하고 운영하려는 코드를 작성했습니다.
그리고 그 과정에서 어디서부터 한계가 발생하는지를 단계별로 확인했습니다.
STEP 1 전체에서 작성한 코드는 다음과 같습니다.
- new 키워드로 직접 의존 객체를 생성하는 POJO 코드
- reflection을 사용해
- 생성자 목록을 조회하고
- 메서드 목록을 조회하고
- 특정 메서드를 호출하는 코드
- 객체를 자동으로 생성·실행하려는 간단한 실행기 코드
- 실행 순서(초기화 → 실행 → 종료)를 보장하려다 실패하는 코드
즉, “프레임워크 흉내를 내는 최소한의 코드”를 직접 만들어 본 단계라고 보시면 됩니다.
STEP 1-1. new 중심 객체 생성의 한계
- 각 객체가 내부에서 new 키워드로 의존 대상을 직접 생성
- 예:
- Service가 Repository를 직접 생성
- Controller가 Service를 직접 생성
문제 1: 객체가 너무 많은 책임을 가집니다
new를 사용하는 순간, 객체는 다음을 모두 책임지게 됩니다.
- 어떤 구현체를 사용할지
- 언제 생성할지
- 몇 개를 생성할지
- 생명주기를 어떻게 가져갈지
즉, 객체가 비즈니스 로직뿐 아니라 운영 책임까지 함께 떠안게 됩니다.
문제 2: 객체 그래프가 코드에 박힙니다
A 객체가 내부에서 new B()를 호출하면,
- A는 B라는 구체 클래스에 강하게 결합됩니다
- 실행 중에 B를 다른 구현으로 교체하기가 거의 불가능해집니다
이 구조에서는
- 테스트 시 Mock을 끼우기 어렵고
- 구조 변경 시 수정 범위가 폭발적으로 늘어납니다
문제 3: 변경이 전파됩니다
의존 대상의 생성자 파라미터가 하나만 바뀌어도, 그 객체를 new 하던 모든 지점을 수정해야 했습니다.

STEP 1-1 정리
- new 중심 구조에서는
- 결합도가 높아지고
- 테스트가 어려워지고
- 변경 비용이 급격히 증가합니다
- 객체 생성과 운영을 중앙에서 관리할 필요성이 드러납니다
STEP 1-2. Reflection으로 자동화를 시도해보기
자동으로 객체를 만들자는 목적의 코드를 작성하였습니다.
- reflection을 사용해
- 클래스의 생성자 목록 조회
- 메서드 목록 조회
- 특정 생성자나 메서드 호출
STEP 1-1의 문제를 겪은 뒤, reflection으로 클래스 구조를 읽어서 자동으로 생성하면 되지 않을까? 라는 생각이 들었습니다.
그래서 실제로 reflection을 사용해
- 생성자 배열을 가져오고
- 메서드 배열을 가져오는 코드를 작성했습니다.
문제 1: 정보는 있는데 기준이 없습니다
reflection은 다음 정보는 잘 제공합니다.
- 생성자가 몇 개인지
- 어떤 메서드가 있는지
- 접근 제어자와 타입 정보
하지만 다음은 확인할 수 없습니다.
- 어떤 생성자를 선택해야 하는지
- 어떤 메서드가 초기화용인지
- 어떤 순서로 실행해야 하는지
즉, 주어진 정보를 활용할 수 없습니다.
문제 2: 판단 로직은 결국 사람이 짜야 합니다
reflection으로 얻은 정보만으로는 실행할 수 없어서,
결국 이런 규칙을 직접 코드로 작성하게 됩니다.
- “파라미터가 가장 많은 생성자를 쓰자”
- “이름이 init으로 시작하면 먼저 호출하자”
STEP 1-2 정리
- reflection은 관측 도구입니다
- 구조를 실행으로 바꾸기 위해서는 다음과 같은 것들이 필요합니다.
- 선택 기준
- 정책
- 규칙
STEP 1-3. Reflection을 직접 운영 코드에 적용했을 때
이 단계에서 작성한 코드
- reflection 기반 객체 생성 로직
- reflection 기반 메서드 호출 로직
- 예외를 잡기 위한 다수의 try-catch
- setAccessible(true)를 사용하는 코드
문제 1: 예외 처리가 폭증합니다
reflection API는 구조상 많은 체크 예외를 발생시킵니다.
- 컴파일 타임에 잡히던 문제가 런타임으로 밀립니다
- 실제 에러는 InvocationTargetException 안에 감춰집니다
결과적으로
- 디버깅이 어려워지고
- 안정성이 떨어집니다
문제 2: 캡슐화가 무너집니다
private 생성자나 메서드를 호출하기 위해 setAccessible(true)를 사용하게 됩니다.
결과적으로, 객체가 스스로 상태를 보호할 수 없게 됩니다.
문제 3: 비즈니스 코드가 오염됩니다
POJO가 순수하게 비즈니스 로직만 담고 있지 못합니다.
어떤 생성자를 쓸지, 어떤 메서드를 언제 호출할지 같은 운영 로직이 스며들기 시작합니다.
STEP 1-3 정리
- reflection을 직접 굴리기 시작하면
- 코드가 지저분해지고
- 규칙이 흩어지고
- 공통 정책을 만들 수 없게 됩니다
STEP 1-4. 실행 순서 문제와 결정적 한계
이 단계에서 작성한 코드
- getDeclaredMethods(), getDeclaredConstructors() 사용
- 반환된 배열을 순서대로 실행하려는 코드
- 실행 순서가 뒤섞되는 상황을 재현한 코드
문제 1: reflection은 순서를 보장하지 않습니다
실제 시스템에서는
- 초기화 → 실행 → 종료 같은 흐름이 반드시 존재합니다.
또한
- A가 준비된 뒤에야 B를 만들 수 있는 의존성 순서가 존재합니다.
하지만 Java reflection API는
- 반환 순서를 보장하지 않습니다
- JVM, 컴파일러, 환경에 따라 달라질 수 있습니다
문제 2: 순서 계약을 표현할 언어적 수단이 없습니다
“이 메서드는 먼저 실행해야 한다”라는 의도는
- 코드나 API에는 표현되어 있지 않습니다
이로 인해
- 별도의 순서 관리 개념이 필요해집니다

STEP 1 전체 결론 정리
STEP 1을 통해 다음 사실이 명확해졌습니다.
- POJO + new 만으로는
객체 생성, 생명주기, 의존성 관리가 분산되어 통제할 수 없습니다. - reflection은 구조를 보여주지만
무엇을 어떻게 실행할지는 결정해주지 않습니다. - reflection을 직접 운영에 쓰기 시작하면
코드 복잡도와 불안정성이 급격히 증가합니다. - 실제 운영에는
- 생성 정책
- 실행 순서
- 생명주기 관리
가 반드시 필요하지만, Java 표준 API만으로는 이를 표현할 수 없습니다.
'spring' 카테고리의 다른 글
| [Spring] spring core 직접 구현해보기 - (2) (1) | 2026.01.23 |
|---|---|
| [Spring] spring-core 직접 구현해보기 - (0) (5) | 2025.12.31 |
| [Spring] 통합 테스트 속도 개선 (2) | 2025.12.15 |
| [SNS] 레디스 세션 스토리지를 활용한 인증 인가 (2) | 2025.10.01 |
| [spring] 1:1 실시간 채팅 구현 (2) | 2025.09.17 |
