나는 spring의 기초부터 배웠다기보다는 정말 구현을 위한 지식만을 쌓았어서 spring이 어떤 면에서 좋은지, 그리고 의존성 주입 부분이 왜 중요한지 잘 몰랐었는데, 스프링 없이 자바로 관련 기능을 구현해보니까 알 수 있게 되었다.
AppConfig로 관심사 분리
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepository;
}
이런 식으로 memberService에서 사용하는 MemberRepository를 생성할 때 코드에서 바로 구현체를 사용해서 생성하면 DIP를 위배한다(클라이언트는 인터페이스만 코드에 써야하는데 지금 구현체도 침범해있다)
이를 해결하기 위해 AppConfig를 사용한다.
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
이렇게 생성자에서 MemberRepository를 받은 후 해당 객체에 주입하도록 하고,
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
}
AppConfig에서 해당 생성자에다가 구현체 객체를 파라미터로 넘겨주는 메서드를 작성한다.
public class MemberApp {
public static void main(String[] args) {
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
}
}
이렇게 하면 memberService를 사용하는 메서드에서 appConfig를 통해서 객체를 만들 수 있다.
이 때 appconfig를 리팩터링 해보면
public class AppConfig {
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 구현할 수 있다. 이렇게 하면 훨씬 각 메서드의 역할이 직관적으로 보이게된다.

이렇게 하면 사용영역과 구성영역이 구별되어, 요구사항이 바뀌어도, 사용영역의 코드는 수정이 필요하지 않게 된다.
DIP와 OCP(기존 코드는 변경하지 않으면서 기능 변경을 할 수 있어야한다.)
IoC, DI, 그리고 컨테이너
Ioc : 제어의 역전
기존 프로그램은 클라이언트 구현 객체가 스스로 필요한 서버 구현 객체를 생성하고, 연결하고 실행했다. 반면, appConfig가 등장한 이후 구현 객체는 자신의 로직을 실행하는 역할만 담당하고, 제어의 흐름은 appConfig가 가져간다
이렇게 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IOC)라고 한다.
프레임워크와 라이브러리
프레임워크 : 내가 작성한 코드를 제어하고, 대신 실행(JUnit)
ex) TestCode에서 @BeforeEach와 @Test가 실행되는데 ,이 로직만 우리가 짜주면 프레임워크가 대신 실행해준다
라이브러리 : 내가 작성한 코드가 직접 제어의 흐름을 담당
ex) Map에서 Json으로 변경할 때 라이브러리의 코드로 직접 내가 실행한다.
DI 의존관계 주입
정적인 클래스 의존관계
클래스가 사용하는 import 코드만 보고 의존관계를 쉽게 판단할 수 있다
위 다이어그램에서 OrderServiceImpl이 MemberRepository와 DiscountPolicy에 의존한다는 것은 고정된 사실이다.
그런데 이 의존관계만으로는 어떤 구현체가 주입될지는 알 수 없다.(실행해야만 알 수 있다.)
동적인 객체 인스턴스 의존관계
애플케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존관계다.
애플리케이션 실행 시점에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것을 의존관계 주입이라고 한다.
의존관계 주입을 사용하면 정적인 클래스 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.
IoC 컨테이너, DI 컨테이너
AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해준다.
최근에는 주로 DI컨테이너라고 불린다.
스프링으로 전환하기
이제까지의 코드를 스프링으로 전환해볼 것이다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
AppConfig는 위와 같이 어노테이션을 추가한다.
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
}
그 다음 main에서는 위와 같이 AnnotationConfigApplicationContext를 활용하여 등록된 bean을 가져온다.
bean의 이름은 해당하는 메서드명이랑 일치한다.
출처
인프런 김영한강사님 - 스프링 핵심원리 기본편
스프링 핵심 원리 - 기본편 강의 | 김영한 - 인프런
김영한 | 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보
www.inflearn.com
'Back-end > Spring' 카테고리의 다른 글
[Spring] 싱글톤 컨테이너 (3) | 2024.11.14 |
---|---|
[spring] 스프링 컨테이너와 스프링 빈 (1) | 2024.10.04 |
[Spring] 객체지향설계와 스프링 (0) | 2024.09.15 |
[Spring] 좋은 객체 지향 설계의 5가지 원칙(SOLID) (2) | 2024.09.15 |
[Spring] 좋은 객체 지향 프로그래밍이란? (0) | 2024.09.15 |