스프링의 핵심 원리는 다형성과 SOLID 원칙을 따르는 설계

 

SOLID 5 원칙

  • 로버트 마틴이 정의한 객체 지향 프로그래밍 설계의 기본 원칙
  • 애자일 소프트웨어 개발과 적응적 소프트웨어 개발의 전반적 전략의 일부

 

더보기

1. SRP (Single Responsibility) - 단일 책임 원칙

  • 하나의 클래스는 하나의 책임만 가져야 한다.
  • 변경이 있을 때 파급 효과가 적게 (ex. 객체의 생성과 사용을 분리)

 

2. OCP (Open Closed) - 개방 폐쇄 원칙

  • 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
  • 인터페이스를 구현한 새로운 클래스 생성, 교체 (기존 클래스 변경 X)

 

3. LSP (Liskov Substitution) - 리스코프 치환 법칙

  • 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스로 교체
  • 인터페이스 규약을 지킬 것

 

4. ISP (Interface Segregation) - 인터페이스 분리 원칙

  • 역할에 따른 세분화된 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
  • 인터페이스가 명확해지고, 대체 가능성이 높아진다.

 

5. DIP (Depengency Inversion) - 의존관계 역전 법칙

  • 구현 클래스에 의존하지 말고, 인터페이스(역할)에 의존 → 구현체를 유연하게 변경

 

구체 클래스에서 의존 관계를 설정하면 SOLID 원칙을 지킬 수 없다. -> 의존 관계를 외부에서 생성, 주입해주어야 한다.

 

public class MemberServiceImpl implements MemberService {
	// MemberRepository 구현체를 변경해야 된다면?
	private final MemberRepository repository = new NormalMemberRepository();
}

 


 

의존관계 주입 (D.I)

  • 애플리케이션 실행 시점에 외부에서 구현 객체를 생성하고 전달해서 의존 관계가 연결되는 것
  • 런타임시에 관계를 동적으로 주입, 결합도를 낮추고 유연성을 확보
  • 구체 클래스에 의존하는 코드 제거 가능

 

public class AppConfig {
	public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
	}
}

 

스프링을 이용한 의존관계 주입

  • 클래스에 @Configuration, 메소드에 @Bean을 붙이면 스프링은 해당 빈들을 스프링 컨테이너에 스프링 빈으로 등록

 

@Configuration
public class AppConfig {
	@Bean
	public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
	}
}
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);
}

 


 

스프링 컨테이너 (ApplicationContext)

  • 스프링 컨테이너는 XML 또는 애노테이션 기반의 자바 설정 클래스(AppConfig.class)로 만들 수 있다.
  • 스프링 빈을 스프링 빈 저장소에 등록

 

ApplicationContext

  • 스프링 컨테이너의 최상위 인터페이스 BeanFactory를 상속
  • 빈 관리 기능 + 편리한 부가 기능을 제공
  • 국제화 기능을 위한 MessageSource
  • 편리하게 리소스를 조회하는 ResourceLoader

 

BeanDefinition

  • @Bean 을 읽어서 메타 정보를 생성
  • 스프링 컨테이너는 메타 정보를 기반으로 스프링 빈 생성
  • 실제로 빈을 사용할때까지 생성을 지연할 수 있음

 

스프링을 왜 써야 하는가?

  • 스프링은 태생이 기업용 온라인 서비스 기술을 지원하기 위해 탄생했다.
  • 순수한 자바 코드의 D.I 컨테이너는 고객의 요청이 올 때마다 객체를 새로 생성 -> 메모리 문제
  • 객체를 하나만 생성하고 공유하도록 설계를 해야 함
  • 싱글톤 패턴의 경우 SOLID 원칙을 지키기가 어려움
  • 스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서객체 인스턴스를 싱글톤(1개만 생성)으로 관리

 

싱글톤으로 관리가 되는 이유?

  • 스프링은 CGLIB라는 클래스의 바이트코드를 조작하는 라이브러리를 사용
  • 실제 클래스를 상속 받은 임의의 클래스를 생성해서(프록시) 스프링 빈으로 등록
  • 설정 파일의 경우 @Configuration 애노테이션이 있으면 내부적으로 CGLIB 동작

 

스프링 빈을 일일이 등록하는 것은 너무 힘들다.

  • @ComponentScan@Component가 붙은 클래스를 확인하여 스프링 빈으로 등록 (선언된 패키지 위치부터)
  • @Repository, @Service, @Controller, @Configuration도 컴포넌트 스캔의 대상이 된다.
  • @SpringBootApplication 내부에도 메타 애노테이션(스프링 지원 기능)으로 @ComponentScan이 있음

 

의존 관계 주입은 어떻게?

  • 생성자 주입, 필드 주입, 수정자 주입, 메서드 주입이 있는데 주로 생성자 주입을 사용
  • 필드 주입의 경우 편리하지만 외부에서 변경이 불가능해서 테스트하기 힘듬, D.I에 의존적
  • 생성자 주입의 경우 한번만 호출되므로 불변하게 설계 가능, final 선언으로 컴파일 시점에서 오류 방지
  • @Autowired 를 사용하면 스프링이 의존관계 자동 주입
 

 

 참고(https://www.inflearn.com/course/스프링-핵심-원리-기본편)

+ Recent posts