[Spring] Spring 핵심 개념 정리

김민범·2024년 11월 12일

Spring

목록 보기
18/29

객체 지향 설계

SOLID 원칙

📚 객체 지향 설계의 5가지 기본 원칙으로, 소프트웨어 설계에서 유지보수성, 확장성, 유연성을 높이기 위한 지침을 제공한다.

  • SOLID 원칙의 종류

    • 단일 책임 원칙 SRP (Single Responsibility Principle)

      • 하나의 클래스는 하나의 책임만 가져야 한다.

      • 클래스는 한 가지 기능에 집중하며, 다른 기능을 담당하지 않아야 한다.

        public class User {
            private String name; // 사용자 정보
            public void login() { /* 로그인 기능 */ }
            public void saveUser() { /* 데이터베이스 저장 기능 */ }
        }
      • 단일 책임 원칙 적용 예시

        public class User { /* 사용자 정보 관리 */ }
        
        public class AuthService {
            public void login(User user) { /* 로그인 기능 */ }
        }
        
        public class UserRepository {
            public void saveUser(User user) { /* 데이터베이스 저장 */ }
        }
    • 개방 폐쇄 원칙 OCP (Open Closed Principle)

      • 소프트웨어 요소는 확장에 열려 있어야 하고, 수정에 닫혀 있어야 한다.

      • 새로운 기능을 추가할 때 기존 코드를 수정하지 않고 확장 가능해야 한다.

        public interface Shape {
            double calculateArea();
        }
        
        public class Circle implements Shape {
            public double calculateArea() { return /* 원의 넓이 계산 */; }
        }
        
        public class Square implements Shape {
            public double calculateArea() { return /* 사각형의 넓이 계산 */; }
        }
        
        public class AreaCalculator {
            public double calculate(Shape shape) {
                return shape.calculateArea();
            }
        }
    • 리스코프 치환 원칙 LSP (Liskov Substitution Principle)

      • 자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다.

        interface Acceleratable {
            void accelerate();
        }
        
        class Car implements Acceleratable {
            @Override
            public void accelerate() {
                System.out.println("내연기관 자동차가 가속합니다.");
            }
        }
        
        class ElectricCar implements Acceleratable {
            @Override
            public void accelerate() {
                System.out.println("전기차가 배터리로 가속합니다.");
            }
        }
    • 인터페이스 분리 원칙 ISP (Interface Segregation Principle)

      • 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.

        public interface Runnable {
            void run();
        }
        
        public interface Swimmable {
            void swim();
        }
        
        public class Dog implements Runnable, Swimmable {
            public void run() { /* 달리기 */ }
            public void swim() { /* 수영 */ }
        }
    • 의존관계 역전 원칙 DIP (Dependency Inversion Principle)

      • 구체적인 클래스에 의존하지 말고, 인터페이스나 추상 클래스에 의존하도록 설계해야 한다.

        interface Notifier {
            void send(String message);
        }
        
        class EmailNotifier implements Notifier {
            @Override
            public void send(String message) {
                System.out.println("Email 알림: " + message);
            }
        }
        
        class NotificationService {
            private Notifier notifier;
        
            public NotificationService(Notifier notifier) {
                this.notifier = notifier;
            }
        
            public void sendNotification(String message) {
                notifier.send(message);
            }
        }

💡 객체 지향의 핵심은 다형성에 있으며, 다형성 만으로는 OCP, DIP를 지킬 수 없다.

Spring과 객체 지향

📚 Spring은 다형성 만으로 해결하지 못했던 OCP, DIP 원칙을 IOC, DI를 통해 지킬 수 있게 도와준다.

  • Spring의 역할
    • OCP, DIP 원칙을 지킬 수 있도록 돕는다.
    • 코드 변경 없이 기능을 확장할 수 있도록 한다.

Spring의 핵심 개념

Spring Container

📚 Spring 애플리케이션에서 객체(Bean)를 생성, 관리, 소멸하는 역할을 담당한다. 설정 파일이나 Annotation을 읽어 Bean을 생성하고 주입하는 모든 과정을 컨트롤한다.

  • Java의 객체 생성

    • 사용하는 클래스에서 직접 생성한다.

    • Spring Container를 사용하면 인터페이스에만 의존하는 설계가 가능하다.

    • Spring Container의 종류

      • BeanFactory: Spring Container의 최상위 인터페이스
      • ApplicationContext: BeanFactory 확장형, Application 개발에 필요한 기능 추가 제공

Spring Bean

📚 Spring 컨테이너가 관리하는 객체이다. 자바 객체 자체는 특별하지 않지만, Spring이 관리하는 순간부터 Bean이 된다. Spring은 Bean의 생성, 초기화, 의존성 주입을 관리한다.

  • Spring Bean이란?

    • Spring Container가 생성하고 관리하는 Java 객체이다.
  • Spring Bean의 특징

    1. Spring 컨테이너에 의해 생성되고 관리된다.
    2. 기본적으로 Singleton으로 설정된다.
    3. 의존성 주입(DI)을 통해 다른 객체들과 의존 관계를 맺는다.
    4. 생성, 초기화, 사용, 소멸의 생명주기를 가진다.
  • Bean 등록 방법

    • XML, Java Annotation, Java 설정파일 등을 통해 Bean으로 등록할 수 있다.

IoC/DI

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

객체의 생성과 관리 권한을 개발자가 아닌 Spring 컨테이너가 담당하는 것.

  • IoC 개념

    1. 객체의 생성 및 생명주기 관리를 컨테이너가 담당.
    2. 객체 간의 결합도를 낮춰 코드 유연성 증가.
  • IoC 예시
    요리사(개발자)가 재료를 직접 준비하지 않고, Chef가 필요한 재료(Bean)를 알아서 관리하고 제공한다.


DI (의존성 주입, Dependency Injection)

Spring이 객체 간의 의존성을 자동으로 주입해주는 기법. IoC를 구현하는 방식 중 하나.

  • DI 개념

    1. 필요한 객체를 Spring 컨테이너가 주입해줌.
    2. 객체 간의 결합도를 낮추고 코드의 유연성과 테스트 가능성을 높임.
  • DI 예시
    Chef가 요리사에게 필요한 재료를 자동으로 가져다주듯, Spring이 필요한 객체를 자동으로 주입.


  • 코드 예시 (Spring 없이 직접 관리)

    MyRepository repo = new MyRepositoryImpl();
    MyService myService = new MyServiceImpl(repo);
    myService.doSomething();
  • 코드 예시 (Spring을 통한 IoC, DI)

    @Service
    public class MyIocService implements MyService {
        private final MyRepository myRepository;
    
        @Autowired
        public MyIocService(MyRepository myRepository) {
            this.myRepository = myRepository;
        }
        // ...
    }
    
    ApplicationContext context = new AnnotationConfigApplicationContext(MyIocApp.class);
    MyService service = context.getBean(MyService.class);

Singleton Pattern

싱글톤 패턴 (Singleton Pattern)

클래스의 인스턴스가 오직 하나만 생성되도록 보장하는 디자인 패턴.

  • 싱글톤 패턴 사용 이유
    • Web Application은 많은 요청을 받으며, 매 요청 시 객체를 생성하면 메모리 낭비 발생.
    • 싱글톤으로 객체를 한 번만 생성해 리소스 절약.

문제점

  • 코드의 양이 많아지고, DIP, OCP 위반.
  • 유연성이 떨어져 안티패턴으로 간주되기도 함.

Spring의 싱글톤 컨테이너

  • Spring Container는 싱글톤 패턴의 문제점들을 해결하면서 객체를 싱글톤으로 관리.
  • Spring Bean은 기본적으로 싱글톤으로 관리됨.

💡 Spring은 요청할 때마다 새로운 객체를 생성하는 옵션도 제공.


싱글톤 패턴의 주의점

  • 상태를 유지하는(Stateful) 객체는 주의 필요
    상태를 유지하는 싱글톤 객체는 데이터 불일치 및 동시성 문제를 유발할 수 있음.

  • 상태 유지 예시

    public class StatefulSingleton {
        private int value;
    
        public void setValue(int value) {
            this.value = value;
        }
        public int getValue() {
            return this.value;
        }
    }
    • 특정 클라이언트가 value 값을 변경하면, 다른 클라이언트에게도 변경된 값이 영향을 미침.

⚠️ Spring Bean은 항상 무상태(stateless)로 설계해야 함.

0개의 댓글