공부하는 안씨의 기록

[정리] 백엔드 Spring 기초 (프레임워크, OOP+POJO, IoC) 본문

KT AIVLE 8기 AI 트랙 활동

[정리] 백엔드 Spring 기초 (프레임워크, OOP+POJO, IoC)

an씨 2025. 11. 25. 09:08

프레임워크란?

  • 프레임워크: 애플리케이션 개발 시 뼈대 제공. 객체의 생성과 소멸을 프레임워크가 관리.
  • 라이브러리: 개발자가 전체적인 사용 흐름을 만듦

즉, 라이브러리는 내가 필요할 때 가져다 써서 호출하는 코드의 모음이지만,

프레임워크는 반대로, 프레임워크가 내 코드를 호출하는 구조/뼈대 이다.

Spring Framework

java 언어 기반의 오픈 소스 애플리케이션 프레임워크 (경량화된 솔루션)

SOLID 원칙에 부합하는 프로그래밍이 가능

  • IoC/DI를 통해 객체 생성, 연결을 자동화
  • AOP로 공통 관심사(로그, 보안, 트랜잭션 등) 분리
  • 웹, 데이터 접근, 보안 등 다양한 모듈을 제공 (모듈: Spring MVC, Spring Boot, Spring JPA 등)

 

OOP + POJO

객체 지향 설계 원칙(solid)

  • SRP : 단일 책임의 원칙(single responsibility principle)
    • 클래스는 단 한개의 책임을 가져야 함
    https://start.spring.io/
  • OCP : 개방 - 폐쇄 원칙
    • 확장에는 열려있어야 하고, 변경에는 닫혀 있어야 한다.
    • 기존의 코드를 변경하지 않고 기능을 수정하거나 추가할 수 있도록 설계해야 한다.
    • OCP는 추상화와 상속 등을 통해 구현해 낼 수 있다.
    • 자주 변화하는 부분을 추상화 하여, 기존의 코드를 수정하지 않고도 기능을 확장시킬 수 있게 설계하여 유연성과 재사용성, 유지보수성을 높이는 것이 핵심이다.
  • ISP : 인터페이스 분리 원칙
    • 객체는 자신이 호출하지 않는 메소드에 의존하지 않아야 한다.
  • DIP: 의존 관계 역전 원칙
    • 상위 모듈이 하위 모듈의 ‘구체적인 구현체에 직접 의존하지 말고, 이 둘을 연결하는 ‘추상화(인터페이스)’에 의존하라는 원칙

제어의 역전: IoC

(운전 제어 예시)

  • 운전자가 하단 프로세스 직접 제어 (제어권이 모두 운전자에게 있다.)
    • 목적지 설정 → 차량 속도 설정 → 신호 및 교통 체계 준수
  • 택시나 대리운전 → 제어권을 운전기사에게 역전. (요청하기만 하면 나머지 프로세스를 운전기사가 처리)

개념

  • 기존: 내가 new 해서 객체를 만들고 연결
  • ioc: 컨테이너가 객체 생성, 연결을 대신 해줌 → 객체 생명 주기 제어권이 개발자에서 컨테이너(프레임워크)로 뒤바뀐다.

Spring IoC 컨테이너와 Bean

💡spring에 의해 생성되고 관리되는 자바 객체를 빈(bean)이라고 한다. 빈(bean)은 스프링 IoC 컨테이너가 관리하는 객체이다.

  • 의존성 관리가 용이.
  • 스프링 컨테이너가 객체 인스턴스를 ‘싱글톤’ 방식으로 관리한다
  • 싱글톤: 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
  • 스프링은 자바 엔터프라이즈 기술을 사용하는 서버 환경이므로, 클라이언트의 요청을 받아 처리할때마다 내부에서 클래스 인스턴스를 계속 생성하게 되면 부하를 감당할 수 없게 된다.
  • 싱글톤 디자인 패턴은 클래스의 객체가 단 하나 존재하게 하여 이러한 문제를 해결해줄 수 있다.

ioc 예시 코드

ioc 없는 코드

public class Galaxy {
    public void powerOn() {
        System.out.println("Hello Galaxy");
    }
}

public class Jihyun {
    private Galaxy phone = new Galaxy();  // 직접 생성

    public void usePhone() {
        phone.powerOn();
    }
}

public class Main {
    public static void main(String[] args) {
        Jihyun jihyun = new Jihyun();  // 모든 의존성을 내부에서 new
        jihyun.usePhone();
    }
}

 

ioc 적용 코드

public interface Phone {
    void powerOn();
}

public class Galaxy implements Phone {
    @Override
    public void powerOn() {
        System.out.println("Hello Galaxy");
    }
}

public class Jihyun {
    private final Phone phone;

    // 생성자 주입
    public Jihyun(Phone phone) {
        this.phone = phone;
    }

    public void usePhone() {
        phone.powerOn();
    }
}

 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public Phone phone() {
        return new Galaxy(); // 어떤 구현체를 쓸지 여기에서 결정
    }

    @Bean
    public Jihyun jihyun() {
        return new Jihyun(phone()); // 스프링이 이 관계를 관리
    }
}

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx =
                new AnnotationConfigApplicationContext(AppConfig.class);

        Jihyun jihyun = ctx.getBean(Jihyun.class);
        jihyun.usePhone();
    }
}