Skip to content

[4주차-안형준] 빈 어노테이션 및 컨트롤러 어노테이션 등록#97

Open
HyungJun-An wants to merge 5 commits into
Loopers-play-dev-lab:HyungJun-Anfrom
HyungJun-An:week4-task
Open

[4주차-안형준] 빈 어노테이션 및 컨트롤러 어노테이션 등록#97
HyungJun-An wants to merge 5 commits into
Loopers-play-dev-lab:HyungJun-Anfrom
HyungJun-An:week4-task

Conversation

@HyungJun-An

Copy link
Copy Markdown
Collaborator

[Week 4] Reflection 기반 다형성 DI 엔진 및 어노테이션 MVC 리팩토링

1. DI 엔진의 진화: 다형성 및 타입 인덱싱 (51c54cb, 8bf6f03)

3주차의 단순 클래스 매핑 방식에서 벗어나, 인터페이스와 상속 구조를 고려한 지능형 DI 엔진으로 리팩토링했습니다.

  • 타입 기반 인덱싱 (Core): 빈 등록 시 해당 클래스의 모든 인터페이스와 부모 클래스를 추적하여 beanNamesByType에 등록.

  • 다형성 지원: 인터페이스 타입으로 @Autowired 주입 요청 시, 인덱싱된 정보를 바탕으로 실제 구현체 빈을 찾아 주입 가능.

  • 책임 분리: 빈 저장소(BeanFactory)와 의존성 주입기(DependencyInjector)의 역할을 명확히 분리하여 구조적 결합도 해제.

2. 설정의 유연성: @configuration & @bean 지원 (3fd12f3)

자동 스캔(@component) 외에 개발자가 직접 빈 생성을 제어할 수 있는 수동 등록 기능을 추가했습니다.

  • 메서드 레벨 빈 생성: 설정 클래스 내 @bean 어노테이션이 붙은 메서드를 리플렉션으로 실행하여 반환된 객체를 싱글톤 빈으로 등록.

  • 동적 설정 환경: 외부 라이브러리나 복잡한 초기화 로직이 필요한 객체도 프레임워크 내에서 관리 가능.

3. MVC 현대화: POJO 및 어노테이션 매핑 (585dde0)

경직된 인터페이스 기반 컨트롤러를 완전히 제거하고, 스프링 스타일의 어노테이션 기반 MVC를 완성했습니다.

  • 인터페이스 의존성 제거: Controller 인터페이스를 삭제하고, 일반 클래스(POJO)에 @controller만 붙이면 컨트롤러로 동작하도록 개선.

  • 핸들러 매핑 엔진: @RequestMapping, @GetMapping 등을 스캔하여 URL-메서드를 1:1로 연결하는 매핑 지도 자동 생성.

  • 실행 책임 분리: 리플렉션을 통한 메서드 호출 로직을 HandlerExecution으로 캡슐화하여 FrontEndController의 실행 로직을 단순화.

💡 주요 리팩토링 포인트 (Summary)

"중복 생성 없는 다형성 빈 관리"

  • 실제 객체는 singletonObjects에 단 하나만 보관하면서, beanNamesByType 매핑을 통해 인터페이스나 상위 타입으로도 동일한 인스턴스를 조회할 수 있도록 설계했습니다.

"경로 정규화를 통한 매핑 안정성"

  • 컨트롤러 상단의 @RequestMapping과 메서드 레벨의 경로를 결합할 때 발생하는 슬래시(/) 중복 문제를 해결하고, 최종 경로를 정규화하여 매핑 실패율을 낮췄습니다.

주요 고민사항

상속 구조 탐색 전략: 재귀(Recursion) vs 반복문(While)

  • 빈 등록 시 상위 클래스와 인터페이스를 추적할 때, 가독성이 좋은 재귀 방식과 스택 오버플로우 위험이 없고 직관적인 while 루프 사이에서 고민했습니다.

  • 결국 현재 구조에서는 깊이가 깊지 않고 제어가 명확한 while 루프를 선택하여 성능과 안정성을 우선시했습니다. (51c54cb)

관심사 분리: 어노테이션 추적의 주체는 누구인가?

@GetMapping 같은 특정 어노테이션을 추적하여 빈을 찾는 기능이 BeanFactory(저장소)의 역할인지, BeanScanner(탐색기)의 역할인지 고민했습니다.

  • 결론적으로 실제 데이터(singletonObjects)를 가진 BeanFactory가 필터링 로직을 직접 구현하게 하여 캡슐화를 유지했습니다.
  • 빈을 찾는 역할이므로 스캐너가 담당하는 것이 직관적이라 판단했지만 BeanScanner는 클래스 패스를 탐색하여 빈 정의를 생성하는 역할입니다. 이미 생성되어 저장된 빈들의 목록까지 알게 되면, 저장소의 내부 구조에 의존하게 되어 캡슐화가 깨지고 책임이 비대해진다고 생각되어 빈 인스턴스 데이터(singletonObjects)를 직접 보유하고 관리하는 BeanFactory가 해당 데이터를 필터링하는 책임을 갖는 것이 가장 적절하다고 결론지었습니다.

빈 생성과 주입의 순서(Lifecycle) 관리

  • @bean 메서드를 통해 생성되는 빈과 @component로 생성되는 빈 사이의 의존성 우선순위를 어떻게 관리할지 고민했습니다.

  • 특히 @configuration 클래스 자체가 먼저 빈으로 등록되어야 내부의 @bean 메서드를 호출할 수 있다는 점을 고려하여 실행 흐름을 설계했습니다.

경로 결합(combinePath) 시 정규화 시점

  • 컨트롤러와 메서드의 경로를 합칠 때, 매번 요청마다 계산할 것인지 아니면 서버 기동 시점에 HandlerMapping 지도에 미리 정규화된 키값으로 등록할 것인지에 대해 고민했습니다. 성능 최적화를 위해 기동 시점에 모든 경로를 정규화하여 저장하는 방식을 선택했습니다.

주요 커밋 로그 (Week 4 Focus)

585dde0 (HEAD) feat: 인터페이스 기반 컨트롤러 삭제 및 어노테이션 기반 매핑 도입

3fd12f3 feat: @configuration 클래스 내 @bean 메서드 빈 생성 기능 추가

8bf6f03 refactor: 타입 기반 빈 조회 도입 및 DI/BeanFactory 역할 분리

51c54cb refactor: 빈 중복 등록 로직 제거 및 다형성 지원

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant