스프링의 핵심 원리는 다형성과 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 를 사용하면 스프링이 의존관계 자동 주입
'Spring' 카테고리의 다른 글
[스프링 MVC2] 메시지, 국제화 (0) | 2022.06.15 |
---|---|
[스프링 MVC2] 타임리프(Thymeleaf) 기본 문법 (0) | 2022.06.14 |
[스프링 MVC1] 서블릿, MVC 패턴 (2/2) (0) | 2022.06.13 |
[스프링 MVC1] 서블릿(Servlet), MVC 패턴 (1/2) (0) | 2022.06.13 |
[Spring] 스프링 핵심 개념 (2/2) (0) | 2022.06.13 |