[Spring] 스프링 숙련 공부1 !

석연걸·2025년 2월 4일

스파르타 코딩클럽

목록 보기
14/17

객체 지향 설계

SOLID 원칙

  • 단일 책임 원칙 (SRP)
    • 하나의 클래스는 하나의 책임만 가져야 한다.
      • 클래스는 한 가지 기능에만 집중해야 하며, 그 외 기능들은 담당하지 않아야 함
    • 3 Layered Architecture 과 유사하다.

  • 개방 폐쇄 원칙 (OCP)
    • 새로운 기능을 추가할 때 기존 코드를 수정하지 않고, 확장할 수 있도록 설계해야한다.
    • 다형성을 활용하여 해결
      • 인터페이스를 상속받은 새로운 클래스를 만들어 새로운 기능을 구현한다.

  • 리스코프 치환 원칙 (LSP)
    • 자식 클래스는 언제나 부모 클래스를 대체할 수 있어야한다.
      • 부모 클래스를 사용하는 곳에서 자식 클래스를 사용해도 프로그램 동작에 문제가 없어야 함
    • 인터페이스를 구현한 구현체를 믿고 사용할 수 있다. (신뢰성이 높음)

  • 인터페이스 분리 원칙 (ISP)
    • 하나의 큰 인터페이스보다 여러 개의 작은 인터페이스로 분리해야 한다.
      • 인터페이스가 명확해짐

  • 의존 관계 역전 원칙 (DIP)
    • 인터페이스나 추상 클래스에 의존하도록 설계해야한다.
    • 모듈간의 결합도를 낮추고, 유연성과 확장성을 높일 수 있다.
    • 서로간의 변경 사항에 독립적이어서 변경에 유연하다.

  • 객체 지향의 핵심은 다형성에 있다. 하지만 다형성만으론 개방 폐쇄 원칙 (OCP)와 의존 관계 역전 원칙 (DIP)를 지킬 수 없다.

IOC / DI

IOC (제어의 역전, Inversion Of Control)

  • 객체의 생성과 관리 권한을 Spring 컨테이너가 담당하는 것을 말하며, Spring에서는 컨테이너가 객체의 생성, 주입, 소멸을 관리한다.

  • IOC의 역할


  • IOC의 개념
    • 객체의 생성 및 생명주기 관리를 Spring 컨테이너가 담당한다.
    • 객체간의 결합도를 낮춰 유연한 코드가 된다.

DI (의존성 주입, Dependency Injection)

  • Spring이 객체 간의 의존성을 자동으로 주입해주는 것

즉, IOC를 통해 Spring 컨테이너에서 Bean을 받아 개발자에게 해당 Bean을 DI 해주는 과정


@ComponentScan

  • Spring이 특정 패키지 내에서 @Component, @Controller, @Service, @Repository 같은 어노테이션이 붙은 클래스를 자동으로 검색하고 이를 Bean으로 등록하는 기능

  • ComponentScan 동작 순서
    1. Spring Application이 실행되면 @ComponentScan이 지정된 패키지를 탐색
    2. 해당 패키지에서 위의 어노테이션이 붙은 클래스를 찾음
    3. 찾은 클래스를 Spring 컨테이너의 Bean으로 등록
    4. 등록된 Bean은 DI와 같은 방식으로 다른 Bean과 연결

Spring Bean은 자동 등록과 수동 등록 두가지가 존재하며, 위의 방식은 자동 등록의 방식이다.

Bean의 수동 등록

  • @Configuration이 있는 클래스를 Bean으로 등록하고 해당 클래스를 파싱해서 @Bean이 있는 메서드를 찾아 Bean을 생성한다.

@Qualifier, @Primary (수동 등록)

  • 같은 타입의 Bean이 중복되어 충돌한 경우 해결하기 위한 어노테이션

  • @Qualifier
    • Bean 등록 시 추가 구분자를 붙여준다.
    • 예시 코드
@Component
@Qualifier("firstService")
public class MyServiceImplV1 implements MyService { ... }

@Component
@Qualifier("secondService")
public class MyServiceImplV2 implements MyService { ... }

@Component
public class ConflictApp {

		private final MyService myService;

		// 생성자 주입에 구분자 추가
		public ConflictApp(@Qualifier("firstService") MyService myService) {
				this.myService = myService;
		}
}

  • @Primary
    • 해당 어노테이션으로 지정된 Bean이 우선순위를 가진다.
    • 예시 코드
@Component
public class MyServiceImplV1 implements MyService { ... }

@Component
@Primary
public class MyServiceImplV2 implements MyService { ... }

@Component
public class ConflictApp {

		private final MyService myService;

		public ConflictApp(MyService myService) {
				this.myService = myService;
		}
}

실제 적용 사례

  • DB가 두 개 존재하는 경우 (메인 MySQL, 보조 Oracle)

    • 기본적으로 MySQL을 사용할 때 @Primary를 사용하면 된다.
    • 필요할 때 @Qualifier 로 Oracle을 사용하도록 만들 수 있다.
    • 두 어노테이션이 동시에 사용되는 경우 @Qualifier의 우선순위가 더 높다.

수동 등록 VS 자동 등록

  • 자동 Bean 등록을 사용하는 이유
    • 다양한 어노테이션으로 쉽게 등록할 수 있다.
    • Spring Boot는 ComponentScan 방식을 기본으로 사용한다.
    • 간단하면서 OCP, DIP를 준수하며 개발할 수 있다.

  • 수동 Bean 등록을 사용하는 경우
    • 외부 라이브러리나 객체를 Spring Bean으로 등록할 때
    • DB 연결과 같이 비즈니스 로직을 지원하는 기술들에 사용
    • 같은 타입의 Bean 여러개 중 하나를 명시적으로 선택해야 될 때
      • @Primary, @Qualifier

Validation (검증)

  • 시스템이 미리 정의한 사양에 부합하는지 검증하는 것
  • Validation을 사용하는 이유
    • 주문서 작성 페이지에서 잘못된 입력값으로 인해 서버에 오류가 발생한다면?
    • 서버의 오류로 인해 작성 페이지에서 오류 페이지로 이동한다면?
    • 오류 페이지로 이동되어 작성중인 폼이 모두 리셋된다면?
    • 위와 같은 상황이 나오지 않기 위해 사용

  • Validation 역할
    • 검증을 통해 적절한 메시지를 클라이언트에게 보여줘야 한다.
    • 검증 오류로 인해 정상적인 동작을 하지 못하는 상황이 없어야 한다.
    • 사용자가 입력한 데이터는 유지되어야 한다.

Binding Result

  • Spring에서 기본적으로 제공되는 Validation 오류를 보관하는 객체
  • 주로 사용자 입력 폼을 검증할 때 많이 쓰이고, Field Error와 Object Error를 보관한다.

Validator

  • @Valid@Validated의 차이점
    • @Valid는 Java 표준이고, @Validated는 Spring에서 제공하는 어노테이션이다.
    • @Validated를 통해 Group Validation 혹은 Controller 이외 계층에서 Validation이 가능하다.

0개의 댓글