좋은 객체 지향 설계의 5가지 원칙의 적용
➡️ SRP 단일 책임 원칙 : 한 클래스는 하나의 책임만 가져야 한다
🔸클라이언트 객체는 직접 구현 객체를 생성, 연결, 실행하는 다양한 책임을 가지고 있었음
🔸관심사 분리 >> AppConfig(구현 객체 생성, 연결) / 클라이언트 객체(실행)
➡️ DIP 의존 관계 역전 원칙 : 추상화에 의존해야지, 구체화의 의존하면 안된다
🔸 클라이언트 코드가 DiscountPolicy 추상화 인터페이스에만 의존하도록 코드 변경
🔸 AppConfig가 FixDiscountPolicy 객체 인스턴스를 대신 생성해서 의존관계를 주입
➡️ OCP : 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다
🔸AppConfig가 의존 관계를 변경해서 클라이언트 코드에 주입하기 때문에 클라이언트 코드 변경x
🔸소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다 (변경할 필요가 없다)
IoC, DI, 그리고 컨테이너
➡️ 제어의 역전 IoC(Inversion of Control)
🔸기존 프로그램은 클라이언트 구현 객체가 스스로 서버 구현 객체를 생성, 연결, 실행했다 ( 프로그램의 제어 흐름을 스스로 조종했다)
🔸AppConfig 등장 이후 구현 객체는 실행의 역할만 가지며 제어 흐름은 AppConfig가 가져간다. 구현 객체는 어떤 객체들이 실행될지 모른다.(단지 실행만)
🔸프로그램에 대한 제어 흐름은 모두 AppConfig가 소유
🔸이렇게 프로그램의 제어 흐름을 직접 제어하지 않고 외부에서 관리하는 것이 제어의 역전(IoC)
➡️ 프레임워크 vs 라이브러리
🔸프레임워크 : 내가 작성한 코드를 프레임워크가 제어하고, 대신 실행 (ex : JUnit)
🔸라이브러리 : 내가 작성한 코드가 직접 제어의 흐름을 담당 (ex : Json, XML등 변환 라이브러리 )
➡️ 의존관계 주입 DI(Dependency Injection)
🔸정적인 클래스 의존관계 vs 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계
🔸정적인 클래스 의존관계 : 실행하지 않아도 분석 가능. 실제 어떤 객체가 주입 될 지는 알 수 없음

🔸 실행 시점에 결정되는 동적인 객체(인스턴스) 의존관계 : 애플리케이션 실행 시점 실제 의존 관계

🔸 의존관계 주입 : 애플리케이션 실행 시점에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는 것
🔸객체 인스턴스를 생성하고, 그 참조값을 전달해서 연결 >> 클라이언트 코드 변경 없이 인스턴스 변경 가능
🔸정적인 클래스 의존관계를 변경하지 않고 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.
➡️ IoC 컨테이너, DI 컨테이너
🔸AppConfig처럼 객체를 생성, 관리하며 의존관계를 연결해주는 것
🔸( = 어샘블러(조립의 의미), 오브젝트 팩토리)
스프링으로 전환하기
➡️ ApplicationContext와 getBean메서드로 스프링컨테이너에 등록 후 사용

package hello.core;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MemberApp {
public static void main(String[] args) {
//AppConfig appConfig = new AppConfig();
//MemberService memberService = appConfig.memberService();
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//AppConfig에 있는 설정정보를 가지고 스프링 컨테이너에 넣어 관리하겠다.
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("member = " + member.getName());
System.out.println("findMember = " + findMember.getName());
}
}
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
❗등록 후 실행 시 로그가 안보이는 경우 resources에 logback.xml파일 생성해 아래 코드 넣어주기❗
(버전 업그레이드로 인해 불필요한 로그 숨김처리 되어있음)
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
➡️ 스프링 컨테이너
🔸ApplicationContext를 스프링 컨테이너라고 한다
🔸기존에는 개발자가 직접 객체를 생성하고 DI를 했지만, 현재는 스프링 컨테이너를 통해 사용
🔸스프링 컨테이너는 @Configuration이 붙은 설정 정보를 사용
🔸@Bean이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록 >> 이 객체를 스프링 빈이라고 함
🔸스프링 빈의 이름은 @Bean이 붙은 메서드 명이 기본
🔸geetBean() 메서드로 스프링 빈(객체)를 찾을 수 있음
'프로그래밍 > - Spring' 카테고리의 다른 글
| [ 스프링 컨테이너와 스프링 빈 ] BeanFactory와 ApplicationContext ~ 스프링 빈 설정 메타 정보 - BeanDefinition (1) | 2025.03.13 |
|---|---|
| [ 스프링 컨테이너와 스프링 빈 ] 스프링 컨테이너 생성 ~ 스프링 빈 조회 (1) | 2025.03.12 |
| [ 스프링 핵심 원리 이해2 ] 객체 지향 원리 적용 : 새로운 할인 정책 개발 ~ 관심사의 분리 (0) | 2025.03.11 |
| [ 스프링 핵심 원리 이해1 ] 예제 만들기(순수 Java) : 주문과 할인 도메인 설계 ~ 주문과 할인 도메인 실행과 테스트 (1) | 2025.03.11 |
| [ 스프링 핵심 원리 이해1 ] 예제 만들기(순수 Java) : 프로젝트 생성~회원도메인 실행과 테스트 (0) | 2025.02.20 |