* 해당 게시물은 김영한님의 [스프링 핵심 원리 - 기본편]을 공부하고 복습용으로 남기는 글입니다.
2년 전 처음 이 강의를 보았다. 그 때는 아 스프링이 이런거구나~하고 넘겼는데
프로젝트를 한 두개쯤 하고 나니까 그제서야 스프링 이론이 군데군데 비어있는게 실감이 나서 복습겸 다시 정리해보았다.
1. 스프링의 등장 배경
- EJB없이도 고품질의 확장가능한 객체 지향 개발이 가능하도록
2. 기존 자바 코드로 서비스를 확장할때의 문제점 (객체 지향 설계의 문제)
의도: 인터페이스를 활용해 OCP,DIP를 잘 지키게 설계
상황: 확장시 의존 관계 때문에 다른 코드로 바뀔 때
-> 추상 인터페이스뿐 아니라 구현 클래스에도 의존하게 되는 문제 (DIP 위반)
-> 클라이언트 코드(`OrderServiceImpl등`)에 종속적인 코드가 생기게 됨 (OCP 위반)
3. 해결 방법
따라서 관심사의 분리 개념이 등장하고 AppConfig라는
구현 객체를 생성하고, 연결하는 책임을 가지는 별도의 클래스를 가짐
AppConfig는 생성자를 통해 참조를 주입해줌 (클라이언트 코드 입장에서 누가 연결될지 외부가 결정하므로 알 필요가 없음)
이제 변경사항이 생길때, 이 AppConfig만 바꾸면 되니 유지보수가 용이
4. 스프링으로 전환
스프링 컨테이너는 XML을 기반으로 만들 수 있고, 애노테이션 기반의 자바 설정 클래스로 만들 수 있음.
`AppConfig` 를 사용했던 방식이 애노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든 것.
ApplicationContext -> 스프링 컨테이너
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
@Configuration과 @Bean으로 설정 정보 등록 (빈이름은 항상 다른 이름을 부여)
5. 싱글톤
스프링은 웹 개발에 특화
웹의 특징: 여러 요청이 동시에 들어옴
원래 appconfig의 동작을 보면, 요청이 올때마다 새로 객체를 만드는데
-> 그럼 JVM 메모리에 계속 객체가 생성되어 올라감
-> 그럼 복잡한 의존성이 엉켜있는 곳에 요청이 계속 올라온다면....
GC가 자주 일어나면 효율이 떨어지니
딱 하나만 생성되고 공유되도록 싱글톤을 보장
그래서 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 함.
그럼 new를 못쓰게 막아야 함
그렇게 하려면 static final 부터 private 생성자 까지 동원하는데,
스프링 컨테이너는 객체를 전부 싱글톤으로 만들어줌
6. 싱글톤 컨테이너
싱글톤의 문제: static 필드 선언, private 생성자 등 지저분한 코드
유연성 하락
DIP 위반: (구체클래스.getInstance)와 같은 코드에서 확인가능
스프링은 이 코드를 빼면서 요청이 올때마다 이미 만든 객체를 제시할 수 있음
참고: 기본 빈 등록 방식은 싱글톤이나, 새로운 객체를 생성하는 것도 가능(빈 스코프에서 확인)
ex) http request 사이클에 맞추거나 할때
싱글톤 방식의 주의점
여러 클라이언트가 하나의 객체 인스턴스를 공유하므로, 절대로 무상태로 설계해야함.
하나의 객체 인스턴스를 공유하므로, 만약 값을 변경하는 필드가 존재한다면...
따라서 set대신 return ~ 과 같이 파라미터 등등을 활용
의문 발생
@Configuration과 싱글톤
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(),discountPolicy());
}
@Bean
public MemberRepository memberRepository(){
return new MemoryMemberRepository();
}
}
여기서 memberRepository()는 new로 MemoryMemberRepository를 호출한다.
다른 2개의 MemoryMemberRepository를 생성하는데 어떻게 싱글톤인가
-> 두 MemoryMemberRepository는 같다
바이트 코드 조작
스프링 컨테이너는 싱글톤 레지스트리
→ 빈이 싱글톤이 되도록 보장해야함
AppConfig를 빈으로 만들어 클래스 타입을 조회하면 CGLIB이라는 값을 확인 가능
스프링 빈을 등록하는 과정에서, 내가 만든 AppConfig가 아니라,
바이트 코드를 조작하는 라이브러리를 가지고 원래 Appconfig를 상속한 다른 클래스를 만들어 등록함
내가 만든건 사라짐
더 자세히 보면
@Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 그 빈을 반환하고, 스프링 빈이 없으면 생성해서 스프링 빈으로 등록하고 반환하는 코드가 동적으로 만들어지는 것이다.
자세한 동작 과정은 모르나 이미 memoryMemberRepository가 있다면
그것을 스프링 컨테이너에서 찾아서 반환하는 코드가 있는듯
참고: @Bean만 써도 스프링 빈으로 등록되지만, 의존관계 주입이 필요해 메서드를 직접 호출하는 경우 싱글톤을 보장하지는 않음
이 내용은 정말 짧게 핵심 원리를 요약한 것이고, 다음 포스팅에 본격적으로 스프링의 기능을 정리해보겠다.
'Spring_Why?' 카테고리의 다른 글
| [Spring/MVC] 스프링 웹 MVC 마무리 (1) | 2025.05.02 |
|---|---|
| [Spring/MVC] 직접 만드는 MVC 패턴 - FrontController 도입 (1) | 2025.04.24 |
| [Spring/MVC] 스프링 MVC 이전의 개발 (0) | 2025.04.16 |
| [Spring/기본] 스프링의 핵심 기능 (2) | 2025.04.11 |