
나름 개발일을 하며 업무적으로 많이 사용해왔던 스프링에 대해 개념,이론적으로 정리가 필요하다고 생각하여 강의를 수강하였다.
김영한 개발자님의 스프링 핵심 원리 - 기본편,고급편 을 수강하며 느낀점들을 기록하려 한다.
• 스프링은 자바 언어 기반의 프레임워크
• 자바 언어의 가장 큰 특징 - 객체 지향 언어
• 스프링은 객체 지향 언어가 가진 강력한 특징을 살려내는 프레임워크
• 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크
• 객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있다.
• 객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프트웨어 개발에 많이 사용된다.
객체 지향의 특징중 다형성의 중요성에 대해 느낄 수 있었다
• 실세계와 객체 지향을 1:1로 매칭X
• 그래도 실세계의 비유로 이해하기에는 좋음
• 역할과 구현으로 세상을 구분

• 역할과 구현으로 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해진다.
• 장점
• 클라이언트는 대상의 역할(인터페이스)만 알면 된다.
• 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
• 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
• 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.
• SRP: 단일 책임 원칙(single responsibility principle)
• OCP: 개방-폐쇄 원칙 (Open/closed principle)
• LSP: 리스코프 치환 원칙 (Liskov substitution principle)
• ISP: 인터페이스 분리 원칙 (Interface segregation principle)
• DIP: 의존관계 역전 원칙 (Dependency inversion principle
예제를 통하여 학습을 진행했다.


위 사진의 주문과 할인 도메인 개발을 진행 하였다.
진행하며 새로운 할인 정책 개발을 통해 새로운 할인 정책을 확장해 보았다.

위 처럼 구현체를 직접 구현하는게 아닌 인터페이스에만 의존하도록 코드를 짜게되면 인터페이스를 참조하는 부분의 소스는 수정이 필요 없게 된다.
public class OrderServiceImpl implements OrderService {
//private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
private DiscountPolicy discountPolicy;
}
하지만 이처럼 사용하려면 구현 객체를 대신 생성하고 주입해주어야 한다.

그 역할을 AppConfig가 담당 하게 된다.

그리고 AppConfig 를 스프링으로 전환하였다.

위의 예제를 진행하며 새로운 할인 정책 개발하여 AppConfig을 통하여 의존성 주입을 통해 클래스들이 단일 책임 원칙을 지키게 될 수 있음을 알 수 있었다.
그리고 개방-폐쇄 원칙에 대해서도 어렴풋이 알게 되었다.
스프링이라는 프레임워크가 추구하는 객체지향 프로그래밍 요소중 IoC컨테이너와, DI컨테이너의 이론에 대해서도 알 수 있었다.
이전시간에 설정했던 AppConfig파일 즉 스프링 컨테이너는 아래와 같이 구성된다.

이러한 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.

package hello.core.beanfind;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" + bean);
}
}
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" + bean);
}
}
}
위 처럼 테스트 코드를 작성하여 BeanDefinition을 이용해 스프링 컨테이너에 등록된 모든 빈을 출력해 보았다.
테스트 중 아래와 같은 유의점들이 있고 해결을 하였다.

지금까지 사용해왔던 대부분의 기능들은 BeanFactory 라는 스프링 최상위 컨테이너 인터페이스가 제공하는 기능들이다.

정리
- ApplicationContext는 BeanFactory의 기능을 상속받는다.
- ApplicationContext는 빈 관리기능 + 편리한 부가 기능을 제공한다.
- BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 - ApplicationContext를 사용한다.
- BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다

스프링 컨테이너는 어노테이션 기반 자바 코드 설정 방식 외에도 다양한 컨테이너 생성이 가능하다. 어떻게 스프링은 이런 다양한 설정을 제공할 수 있을까?

바로 BeanDefinition 을 통해 역할과 구현을 개념적으로 나눈 것이기 때문이다.
BeanDefinition이란 무엇일까? BeanDefinition을 스프링 빈 설정 메타 정보라 한다.
BeanDefinition이라는 추상화의 기능은
