- 객체지향 프로그래밍 (OOP): 스프링 프레임워크는 객체지향 프로그래밍에 기반하며, 서버 개발 시 일반적으로 3계층 (Controller, Service, Repository)로 나눠서 개발합니다. 이를 통해 코드의 재사용성이 높아지며, 필요한 기능들을 모듈화하여 쉽게 활용할 수 있습니다.
모듈화가 잘 되어 있어, 필요한 모듈들만 레고처럼 조립하여 사용 가능 ex) 스프링 시큐리티, 스프링 타임리프, 스프링 Data JPA 등 - DI (의존성 주입): 스프링은 DI를 지원하여 강한 결합을 완화시키고, 코드의 유연성을 높여줍니다.
- 비즈니스 로직에 집중: 스프링은 프레임워크의 다른 부분들이 클라이언트와 데이터베이스 간의 통신을 처리하므로, 개발자는 비즈니스 로직에 집중할 수 있습니다.
- 그 외: AOP 지원, 테스트 코드 작성의 용이성, 20년 넘게 발전해온 신뢰성 있는 프레임워크 등도 스프링 프레임워크의 중요한 특징입니다.
Enterprise applications 개발 편의성 제공(스프링은 기업용 애플리케이션의 요구사항 해결에 초점을 맞춘 프레임워크)
스프링 프레임워크는 어떤 특징 혹은 장점을 가지고 있나요? (3가지 이상)
- 의존성 주입(Dependency Injection, DI): 스프링은 DI를 통해 객체 간의 의존성을 외부에서 관리합니다. 이를 통해 객체 간의 결합도를 낮추고, 유연성과 테스트 용이성을 높일 수 있습니다.
- 프레임워크의 모듈화: 스프링은 여러 모듈로 구성되어 있어 필요한 기능만 선택하여 사용할 수 있습니다. 예를 들어, 스프링 MVC를 이용한 웹 개발, 스프링 Security를 이용한 보안, 스프링 Data JPA를 이용한 데이터베이스 접근 등이 있습니다.
- 트랜잭션 관리: 스프링은 선언적 트랜잭션 관리를 지원하여, 코드 레벨에서 트랜잭션 처리를 할 필요 없이 트랜잭션을 설정하고 관리할 수 있습니다. 이를 통해 코드의 복잡도를 줄일 수 있습니다.
- AOP(Aspect-Oriented Programming) 지원: 스프링은 AOP를 지원하여, 비즈니스 로직과 각종 공통 기능(트랜잭션, 로깅, 보안 등)을 분리하여 개발할 수 있습니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.
- 테스트 용이성: 스프링은 JUnit과 같은 테스팅 프레임워크와 잘 통합되어 테스트하기 쉬운 구조를 가지고 있습니다. DI와 AOP의 지원으로 단위 테스트와 통합 테스트를 편리하게 수행할 수 있습니다.
- 다양한 데이터 접근 기술 지원: 스프링은 JDBC, JPA, Hibernate 등 다양한 데이터 접근 기술을 지원하며, 이에 대한 템플릿을 제공합니다. 이를 통해 데이터베이스 연동 작업을 쉽게 처리할 수 있습니다.
스프링에서 DI (의존성 주입) 를 사용하는 이유가 무엇인가요? 예를 통해 설명 해 보세요.
- 결합도를 낮춤: DI를 사용하면 객체들 간의 결합도가 낮아집니다. 결합도가 낮다는 것은 하나의 객체가 다른 객체에 대해 알아야 하는 정보가 적다는 뜻입니다. 이로 인해 코드의 수정이 필요한 경우에도 다른 코드에 주는 영향을 최소화할 수 있습니다.
- 유연성과 확장성 향상: DI를 사용하면 인터페이스를 기반으로 프로그래밍할 수 있어, 코드의 유연성과 확장성이 향상됩니다. 필요에 따라 다른 구현체를 주입할 수 있으므로, 코드 수정 없이도 기능의 변경이나 추가가 가능합니다.
- 테스트 용이성 증가: DI를 사용하면 테스트 시에 테스트 대상 객체의 의존 객체를 쉽게 대체할 수 있습니다. 이를 통해 테스트하기 어려운 요소(외부 API, DB 등)를 가짜 객체(Mock Object)로 대체하여 테스트를 수월하게 진행할 수 있습니다.
의존성을 주입함으로써 높은 결합도를 느슨하고 유연하게 한다.(느슨한 결합(loose coupling)
클래스 A에서 B라는 객체를 사용해야 할 때 B 인스턴스를 생성하면(B b = new B()) 두 객체는 높은 결합도를 가지게 된다. 반면, A 클래스에서 B가 필요하다는 정의만 내리고(B b;) B 객체를 주입하는 것은 외부에서 이루어지도록 하면 결합도를 느슨하게 할 수 있다.
객체를 주입하는 방법에는 3가지가 있는데 필드 주입, setter 주입, 생성자 주입이다.
여기서 생성자 주입을 가장 권장 한다. 그 이유로는
- 필드 주입으로는 순환 의존성을 파악하기 어려움. 생성자 주입을 하게 되면 서버 기동 시 순환 의존성을 가지는 요소들을 파악할 수 있게 에러메시지를 표시하면서 서버 기동이 되지 않는다.
- 불변성(Immutability) 보장 : 필드 주입은 final을 선언할 수 없지만 생성자 주입은 final을 선언함으로써 객체가 변하지 않도록 방지해준다. 객체의 안정성을 높힌다.
- 단일 책임 원칙 준수(Single Responsibility Principle) : 생성자에서 주입 받는 의존성이 너무 많을 경우 해당 클래스가 너무 많은 역할을 담당하고 있는지 여부 체크
스프링 프레임워크의 핵심은 IoC(Inversion of Control)와 DI(Dependency Injection)로, 이 두 가지 개념이 스프링의 빈 생명 주기 및 빈 간의 관계 설정에 크게 영향을 미칩니다.
IoC(Inversion of Control) :
'제어의 역전'이라는 의미로, 객체의 생성과 생명 주기를 개발자가 아닌 프레임워크가 담당하는 개념입니다. 일반적으로 개발자는 직접 new 키워드를 사용해 객체를 생성하고, 객체간의 의존성을 설정합니다. 그러나 이러한 접근 방식은 코드가 매우 결합력이 높아져 유지 보수가 어렵다는 단점이 있습니다. 이를 해결하기 위해 IoC는 객체의 생성과 생명 주기를 프레임워크가 담당하도록 하여 코드의 결합력을 줄이고 유지 보수성을 향상시킵니다.
DI(Dependency Injection) :
'의존성 주입'이라는 의미로, 객체간의 의존성을 코드 내에서 직접 명시하는 것이 아니라 외부(즉, 프레임워크)에서 주입하는 방식을 의미합니다. DI는 IoC의 구현 방법 중 하나로, 클래스 내부에서 생성자나 setter 메소드를 통해 의존성을 주입받습니다.
스프링에서는 이러한 IoC와 DI 개념을 이용해 BeanFactory나 ApplicationContext와 같은 컨테이너를 통해 객체(Bean)의 생명 주기를 관리하고, Bean 간의 의존성을 주입합니다.
Singleton Bean :
스프링에서 Bean은 기본적으로 Singleton Scope를 가지며, 이는 동일한 타입의 Bean이 요청되면 항상 같은 인스턴스를 반환함을 의미합니다. 이렇게 함으로써 메모리 효율성과 성능 최적화를 도모할 수 있습니다. 하지만, Singleton Bean은 상태를 가지면 안 되며, 그렇지 않으면 동시성 문제가 발생할 수 있습니다. 이러한 이유로, Singleton Bean은 일반적으로 무상태(stateless)로 설계되어야 합니다.
하지만 모든 상황에서 Singleton Scope가 최선은 아닙니다. 때로는 Prototype, Request, Session 등 다른 Scope를 가진 Bean이 필요할 수 있습니다. 이는 애플리케이션의 요구사항에 따라 달라집니다.
따라서 스프링 프레임워크는 개발자로 하여금 복잡한 객체 생성 및 생명 주기 관리, 그리고 의존성 설정 작업으로부터 벗어나게 하여, 개발자가 비즈니스 로직에 집중할 수 있게 합니다.
또한, 스프링 컨테이너는 개발자가 설정한 메타데이터(@Annotation, XML, Java Config 등)를 바탕으로 이러한 작업을 수행합니다. 이는 개발자가 의존성 관계를 코드 상에서 직접 작성하는 것이 아니라 외부에서 설정하게 함으로써, 코드의 결합도를 낮추고 유연성을 향상시킵니다.
스프링에서는 BeanFactory와 ApplicationContext 등 다양한 컨테이너가 제공되며, 이 중에서는 특히 ApplicationContext가 가장 일반적으로 사용됩니다. ApplicationContext는 BeanFactory의 모든 기능을 포함하고 있을 뿐만 아니라, 다양한 엔터프라이즈 지원 기능을 추가적으로 제공합니다. 이러한 기능에는 국제화 처리, 이벤트 발행, 리소스 로딩 등이 포함됩니다.
결국, 스프링 프레임워크의 핵심 기능은 이러한 IoC와 DI를 이용하여 개발자 대신에 복잡한 객체 생성 및 생명주기 관리 작업을 수행하고, 이를 통해 코드의 결합도를 낮추고 유연성을 향상시키는 것입니다. 이로써 개발자는 더 깔끔하고 유지보수가 용이한 코드를 작성할 수 있게 됩니다.
'Spring' 카테고리의 다른 글
AOP(Aspect-Oriented Programming) (0) | 2023.05.29 |
---|---|
Transaction, Primary, Replica (0) | 2023.05.29 |
스프링 3계층 아키텍처, Annotation(@) (0) | 2023.05.25 |
JPA(Java Persistence API), ORM(Object-Relational Mapping) pt.2 (0) | 2023.05.25 |
절차지향(Procedural), 객체지향(Object-Oriented), 관점지향(Aspect-Oriented) 프로그래밍 pt.2 (0) | 2023.05.25 |