스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com
강의를 들으며 생각 정리
앞서 회원주문관리프로그램을 객체 지향 원리에 기반하여 개발해 보았다.
순수 자바 코드로 개발을 진행했지만 다형성 + OCP, DIP를 만족하는 이미 좋은 프로그램인 것 같은데, 스프링을 왜 사용해야 할까? 스프링을 사용함으로써 얻는 이점은 무엇일까? 이에 대해 공부한 내용을 정리해 본다.
IoC, DI, 그리고 컨테이너
스프링으로 진입하기 전, 먼저 기본 개념에 대해 알아보자.
IoC, 제어의 역전
기존 프로그램은 클라이언트 구현 객체가 프로그램의 제어 흐름을 스스로 조종했다. 이는 역할이 제대로 분리되지 않았음을 앞서 살펴보았다. 그러나 AppConfig의 등장으로 클라이언트 구현 객체는 자신의 로직을 실행하는 역할만 담당하고 AppConfig가 그 제어 흐름을 가져갔다. 이렇듯 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)이라 한다.
여기서 내가 작성한 코드(ex. AppConfig)가 직접 제어의 흐름을 담당한다면 라이브러리에 속하고 프레임워크가 내가 작성한 코드를 제어하고, 실행한다면 그것은 프레임워크(ex. JUnit)가 맞다. 즉, 내가 작성한 코드인 AppConfig가 아닌 스프링 프레임워크가 직접 객체들을 제어해 준다면 보다 편리하게 개발을 진행할 수 있을 것이다.
의존관계 주입 DI
DI에 대해서 알아보기 전에 두 의존관계의 차이점을 알아보자.
<정적인 클래스 의존관계>
클래스가 사용하는 import 코드만 보고 의존관계를 쉽게 판단할 수 있다. 즉, 눈으로 확인할 수 있는, 애플리케이션을 실행하지 않아도 분석할 수 있는 의존관계를 말한다. 그러나 이러한 클래스 의존관계 만으로는 실제 어떤 객체가 인터페이스에 주입 될지 알 수 없다.
<동적인 클래스 의존관계>
애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계이다.
여기서 애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결 되는 것을 의존관계 주입이라 한다.
-> 중요한 점은 의존관계 주입(DI)을 사용하면 정적인 클래스 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다는 것이다.
DI 컨테이너
AppConfig처럼 객체를 생성하고 관리하면서 의존관계를 연결해 주는 것을 IoC 컨테이너 또는 DI 컨테이너라 한다.
스프링으로 전환하기
지금까지 순수 자바 코드만으로 DI를 적용했는데, 이제 스프링을 본격적으로 사용해 보자.
전체 코드는 깃허브에 올려 놓았다.
AppConfig
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(),discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy(){
return new RateDiscountPolicy();
}
}
AppConfig를 다음과 같이 변경할 수 있다.
@Configuration은 간단하게 스프링 설정 정보를 하는 역할이다. 자세한건 나중에 싱글톤을 공부할 때 알아보자.
각 메소드 마다 @Bean을 추가함으로써 각 메소드의 반환 객체를 스프링 컨테이너에 등록한다. 여기서 반환 객체를 스프링 빈이라고 한다.
이제 메인 메소드를 수정해보자.
MemberApp
public class MemberApp {
public static void main(String[] args) {
//AppConfig appConfig=new AppConfig();
//MemberService memberService=appConfig.memberService();
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find Member = "+findMember.getName());
}
}
기존 AppConfig를 직접 호출하는 것이 아닌 ApplicationContext 객체를 사용한다.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
스프링 컨테이너
ApplicationContext는 스프링 컨테이너이고, 위 코드는 AppConfig의 환경설정 정보를 통해 스프링 빈을 컨테이너에 등록하는 역할을 한다. 빈을 전부 등록했다면 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.
스프링 컨테이너는 다양한 설정 형식을 지원한다.(java, xml 등) 이는 다양한 형식의 코드들을 BeanDefinition이라는 빈 설정 메타정보로 추상화시켜 사용하기 때문이다. 스프링 컨테이너는 JAVA 코드인지, XML 코드인지 몰라도 된다. 오직 BeanDefinition만 알면 되기 때문에 역할과 구현을 개념적으로 잘 나눈 사례이다.
스프링 빈
getBean 메소드는 컨테이너에서 스프링 빈의 name으로 해당 Bean을 꺼낸다. 이제 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 변경된 것이다.
getBean과 관련해 스프링 빈을 조회하는 여러가지 방법이 있는데 깃허브에 올린 테스트 코드를(beanfind)를 참고하자.
이렇게 개발한 내용을 스프링 프레임워크를 통해 실행될 수 있도록 간단한 설정을 추가하였다. 다음 포스팅에서는 스프링 컨테이너의 싱글톤에 대해서 알아본다.
'java > spring' 카테고리의 다른 글
[Spring] 컴포넌트 스캔 (0) | 2021.01.08 |
---|---|
[Spring] 싱글톤 컨테이너 (0) | 2021.01.08 |
[Spring] 스프링 핵심 원리 이해2 - 객체 지향 원리 적용 (0) | 2021.01.06 |
[Spring] 스프링 핵심 원리 이해 1 - 예제 만들기 (0) | 2021.01.06 |
[Spring] 객체 지향 설계와 스프링 (0) | 2021.01.03 |