상세 컨텐츠

본문 제목

Spring, Bean, IoC, DI 개념에 대한 정리

기록 - 프로그래밍/Spring

by wjjun 2021. 10. 19. 23:16

본문

Spring을 사용하는 이유

자바 언어를 이용해 엔터프라이즈 시스템을 개발하기 위한
"보다 나은 방법과 전략"을 Spring을 통해 활용할 수 있습니다.

Spring에서 제공하는 전략과 방법

어플리케이션을 개발하는데 스프링은 '공통 프로그래밍 모델'을 제공합니다.
공통프로그래밍 모델로는 "IoC, DI, AOP, 서비스 추상황"가 있습니다.

결국 이러한 방법이 나온 이유는
개발자가 비즈니스 로직과 개발에 집중할 수 있도록 만들기 위함입니다.

Spring 장점

1.단순함
EJB(Enterprise JavaBeans)를 서비스 코드에 사용해본 적은 없지만 EJB 복잡한 기술을 단순화 하여 자바의 객체지향 언어의 장점을 살릴 수 있도록 도와주는 도구입니다.

2.유연함

스프링은 확장성이 높습니다. 플러그인, 라이브러리, 다른 프레임워크와 같은 Third-party 지원을 많은 곳으로부터 받고 있습니다.

그러면서 안정적입니다. 코드 베이스를 크게 변경하거나 하는 일이 없었기 때문입니다.

 

정리해 보면, Spring 사용하면

(1) 단순함을 통해 자바 언어의 장점인 객체지향 프로그래밍을 잘할 있습니다.

(2) 유연함을 통해 빠르게 개발을 있습니다.

 

객체지향 프로그래밍이란 무엇

하나의 패러다임입니다.
패러다임(wikipedia 사전적 의미) : 한 시대의 사람들이 공동으로 생각하고 있는 "이론적인 틀과 체계"를 의미하는 개념으로 표현하고 있습니다.

프로그래밍을 왜 해야 하는가?
소프트웨어는 왜 필요할까?

문제를 해결하기 위함입니다.
객체지향 프로그래밍이라는 것도
결국, 문제를 분석하고 "설계할 때 사용되는 하나의 효율적인 방법"이라고 생각합니다.
그리고 현재 시대에서 공동으로 사람들이 인정하고 사용하고 있는 하나의 틀과 체계이기 때문에 우리는 이러한 개념을 알아야 한다고 생각합니다.

객체지향 프로그래밍 방법

1.객체 생성
필요한 데이터는 추상화하여 상태와 행위를 가진 객체로 만들게 됩니다
문제를 나누고 분석하는 작업

2.객체 협렵
객체들 간에 유기적으로 연결되어 하나의 로직이 만들어 집니다
작업을 조직화하는 설계 작업 (객체지향 프로그래밍의 기본원칙 SOLID 설계 원칙을 따르게 됩니다)

객체지향의 설계원칙 SOLID

SRP 단일책임원칙
Single Responsibility 단어의 의미를 그대로 해석한 것처럼
하나의 클래스는 하나의 책임만을 갖는 것입니다.
클래스를 변경해야 하는 이유는 단 하나여야 합니다.
서로 다른 요청자가 의존하는 코드가 있다면 이 클래스는 분리되어야 합니다.

OCP 개방폐쇄원칙
확장에는 open 열려있고, 변경에는 close 닫혀 있어야 합니다.
기존 클래스를 수정하지 않고 확장을 할 수 있어야 합니다.
방법 1, 상위 클래스를 상속 받아 기존의 기능을 유지한 상태로 새로운 기능을 확장합니다.
방법 2, 확장(변화)되는 부분을 인터페이스로 추상화 합니다.

LSP 리스코프 치환원칙
서브 타입은 기반 타입으로 치환하여 사용이 가능해야 합니다.
(1) Type A의 객체 a1 (서브)
(2) Type B의 객체 b1 (기반)

Type B를 프로그램 C에 정의하였음에도
b1 객체를 사용하는 대신 a1 객체로 치환하여 프로그램 C가 동일하게 동작이 된다면
서브 Type A는 기반 Type B로 치환 가능하므로 LSP 원칙을 준수하개 됩니다.

상위 타입의 객체을 하위 타입의 객체로 치환하여도
상위 타입을 사용하여 동작하고 있던 프로그램은 정상적으로 동작되어야 합니다.

ISP 인터페이스 분리원칙
범용적인 하나의 인터페이스를 사용하지 않고 특정 클라이언트를 위한 여러개의 인터페이스를 갖는 것이 더 낫습니다



DIP 의존관계 역전원칙
추상화에 의지해야지 구체화에 의지하면 안된다는 의미입니다.
풀어서 읽어보면,
고수준 모듈은 저수준 모듈에 의존하면 안됩니다.
저수준 모듈이 고수준 모듈에서 정의한 "추상 타입(추상적 자료형)에 의존"해야 하는 것을 의미합니다.



객체를 생성하고 객체간의 유기적인 협력 관계를 맺었다
그럼, 이제 객체를 사용하면 되는가?

그 전에, Spring에서 객체가 사용되는 방법을 알아보고자 합니다

Spring Bean 정의

객체가 Bean으로 등록되어질 수 있도록 정의되어야 합니다.
객체 Bean 등록은 XML 파일 내 정의하는 방식과 Annotaion으로 정의할 수 있습니다.

Spring Bean 등록

Bean으로 정의된 객체는 Application을 실행시키면
SpringApplication 클래스의 run() 메소드가 실행되어지고
SpringApplication 클래스의 prepareContext() 내부에서
정의된 Bean 목록을 가져와 DefaultSingletonBeanRegistry 클래스의
addSingleton() 또는 registerSingleton() 안에서
싱글톤 스코프로 Bean Instance를 등록하여 관리하는 것으로 확인됩니다.

Spring IoC Container

등록된 Bean을 모아놓고 관리하기 위한 공간이라는 의미에서 컨테이너라고 부르게 되었습니다.
등록된 Bean 생성, 관계, 사용, 삭제, 생명주기에 대한 관리를 컨테이너에서 담당하고 있습니다.
스프링에서 IoC Container 역할을 맡는 최상위 인터페이스는 BeanFactory 입니다.
그리고 실제로 어플리케이션에서 주로 사용하고 있는 인터페이스의 구현 클래스로는 ApplicationContext가 있습니다.

ApplicationContext는 아래 클래스들을 상속받아 역할을 맡고 있습니다.
1.EnvironmentCapable : 실행 환경을 만드는 역할
2.ListableBeanFactory : Bean 가져오는 역할
3.DefaultListableBeanFactory : 같은 하위 클래스에서 실체 구현 bean 저장하는 자료구조 ConcurrentHashMap 사용
4.HierarchicalBeanFactory : 부모 BeanFactory 설정
5.MessageSource : 다국어 지원 messageSource.getMessage((“Greeting”), Local.KOREA)
6.ApplicationEventPublisher : 이벤트 역할
7.ResourcePatternResolver : 리소스를 읽어오는 역할

실제 Bean을 관리하기 위한 기능은 BeanFacotry 상속 받은 ListableBeanFactory 인터페이스를 상속 받아
Bean 관리에 필요한 기능들을 수행하고 있습니다.

IoC

Inversion of Control 용어의 약자로 제어의 역전이라는 의미입니다.

스프링으로 구현된 프로그램이 실행될 때 객체에 대한 제어권이
실행되어지고 있는 클래스에서 IoC Container로 제어권이 역전되어지는 것을 의미합니다.

객체를 직접 만들지 않고 제3자를 통해 '주입'을 받아 동작하는 프로그램이 IoC 개념이 적용된 것을 의미합니다.

IoC 아닌 것

1.의존 객체를 직접 만들어서 사용하는 경우입니다.

Food food = new Food();

 

IoC 인 것

1.Java에서는 생성자 Parameter를 이용하여 객체를 주입 받아 사용하는 경우입니다.
BookService 클래스에서 객체를 직접 생성하여 사용하는 것이 아닌
이미 만들어져 있는 객체의 인스턴스를 주입받기 위해 제어권이 일시적으로 BookRepository 역전되어지는 것을
IoC 개념이 적용되었다는 것을 의미합니다.

public class BookService {
    public BookService (BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }
}

 

2.Spring에서는 BeanFactory가 관리하는 등록된 Bean의 레퍼런스를 주입받아 사용하는 경우
bookRepository 객체를 사용하기 위해서는
BookService 클래스에서 일시적으로 제어권이 Spring IoC Container로 이동하여
필요한 bookRepository 인스턴스를 받아오는 것을 통해 IoC 개념이 적용되어진 것을 확인할 수 있습니다.

@Service
public class BookService {
    @Autowired
    public BookRepository bookRepository;
}

 

말씀드린 1, 2번을 나누어 설명드린 것처럼 언어, 프레임워크에 종속되지 않고
IoC 개념을 적용할 수 있다는 것을 확인할 수 있었습니다.

DI

Dependency Injection 영어는 의존성 주입이라는 의미로
의존성 주입을 통해 오브젝트 레퍼런스를 외부로부터 제공받는 것을 의미합니다.

IoC와 DI 단어의 의미가 구분이 잘 되어지지 않는다고 생각되어
개인적으로 두 가지의 개념을 구분하여 정리해본 것으로.
IoC 의미는 제어권이 역전되었다는 개념을 의미하며
DI 의미는 실행 주체가 아닌 제3자로 인해 주입이 되었다는 개념을 의미한다고 생각을 정리하였습니다.
의존성 주입의 목적은 오브젝트간 다이내믹한 의존관계를 만들기 위해 사용됩니다.

DI 주입 의존관계 조건

일반적인 주입의 개념이 아닌 DI 주입이라면 런타임 시점에 코드상에서
어떤 객체를 생성할 것인지 알 수 없어야 합니다.

그러한 조건을 만족하기 위해서 3가지 조건에 부합해야 합니다.
1.런타임 시점에 의존관계가 드러나지 않아야 하므로 '인터페이스'에만 의존해야 합니다.
2.런타임 시점의 의존관계는 IoC Container, Bean Factory 같이 제 3자에 의해 결정됩니다.
3.의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)받아 만들어집니다.

관련글 더보기

댓글 영역