Spring

[Spring Core] 스프링을 사용하는 이유?

mxruhxn 2025. 2. 15. 20:27
728x90
반응형

객체 지향 설계와 다형성의 중요성

  • 객체 지향 프로그래밍은 추상화, 캡슐화, 상속, 다형성 등으로 구성되며, 특히 다형성은 역할(인터페이스)과 구현(구현체)을 분리하여 유연하고 확장 가능한 코드를 작성할 수 있게 한다.
  • 문제점: 단순히 다형성을 사용해도 클라이언트 코드가 구체 구현에 의존하게 되어, 구현체 변경 시 클라이언트 코드도 수정해야 하는 문제가 발생할 수 있다.
    • = 다형성만으로는 OCP(개발-폐쇄 원칙), DIP(의존관계 역전 원칙)를 지킬 수 없다

문제 해결: 스프링을 사용하지 않는 경우

다형성만으로는 OCP와 DIP를 지킬 수 없다는 것을 알아보았다. 즉, 변경 시 클라이언트 코드의 변경이 필요하다는 것이다. 이러한 문제는 구현체에 대한 코드가 클라이언트 코드에 그대로 노출되어 있기 때문에 발생한다.

 

즉, 이를 해결하기 위해서는 클라이언트 코드에는 구현체를 노출하지 않고 인터페이스만 노출, 즉 클라이언트 코드가 인터페이스에만 의존하도록 해야 한다. 그렇다면 실제 구현체는 어떻게 주입해줄 수 있을까?

 

=> 외부 설정 클래스를 따로 두는 것이다.

 

다음의 코드를 보자

AppConfig

package com.study.springcore;

import { ... }

public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository()); // 생성자 주입.
    }

    private static MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }

}
  • AppConfig는 애플리케이션의 실제 동작에 필요한 구현 객체를 생성한다.
  • AppConfig는 생성한 객체 인스턴스의 참조(레퍼런스)를 생성자를 통해서 주입(연결)해준다.
    • 클라이언트인 memberServiceImpl 입장에서 보면 의존관계를 마치 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection)이라고 한다.
  • AppConfig를 보면 역할과 구현 클래스가 한 눈에 들어온다. 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악할 수 있다
  • 프로그램의 흐름을 클라이언트 코드에서 직접 제어하는 거싱 아니라, AppConfig라는 외부 클래스를 통해 관리하는 것을 '제어의 역전(IoC)'라고 한다.

MemberServiceImpl

package com.study.springcore.member;

public class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.saev(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findbyId(memberId);
    }
}
  • 클라이언트 코드에 해당하는 MemberServiceImpl은 구현체인 MemoryMemberRepository에 대해 알지 못한다.
    • 즉, 어떤 구현체가 주입될지 알 수 없으며, 오로지 인터페이스(MemberRepository)에만 의존한다.
  • 즉, 외부 객체를 통한 DI로 DIP를 달성했으며, 객체의 생성과 비즈니스 로직의 실행이라는 관심사도 서로 분리할 수 있었다.

스프링을 사용하지 않을 경우, 외부 클래스를 통해 DI를 수행하여 OCP와 DIP를 달성할 수 있었다. 하지만, 이러한 IoC, DI 등을 기본으로 지원하며 수많은 추가 기능을 편리하게 제공해주는 프레임워크가 바로 '스프링'이다.

 

=> 스프링을 활용하면 더욱 원활하게 객체지향적인 개발을 할 수 있다.

여기서 만들어본 AppConfig라는 클래스는 스프링에서 DI 컨테이너(= IoC 컨테이너)라고 불린다. 이러한 DI 컨테이너가 전체 애플리케이션이 어떤 흐름으로 제어하고 실행될지를 결정한다.

 

다음 포스팅에서 Spring에 대해 더 자세히 알아보자!!

728x90
반응형