개요
Spring은 로드 존슨이 당시 주류였던 EJB2의 단점을 보완하여 개발하였다. Spring은 Jakarta EE 개발을 더 쉽게 만드는 것을 목표로 한다. Sping의 장점은 다음과 같다.
- 가볍다 (Lightweight)
- EJB2는 무겁고 복잡한 구조를 가지고 있었다
- Spring은 경량 컨테이너를 사용하여 구동 속도가 훨씬 가볍고 더 빠르다
- POJO 기반 프로그래밍 (Plain Java Old Object)
- EJB2는 특정 인터페이스를 구현해야 하는 등 많은 제약이 있었다
- Spring은 POJO를 사용하여 더 간단하고 객체지향적으로 개발할 수 있다
- DI (Dependency Injection), IoC (Inversion of Control)
- Spring은 Dependency Injection을 통해 객체 간의 결합성을 낮춘다
- 이는 유지보수성과 테스트 용이성을 높이며 코드의 재사용성을 증가시킨다
- EJB2는 기본적으로 DI를 지원하지 않는다. EJB2에서는 개발자가 직접 JDNI(Java Naming and Directory Interface) Lookup 코드를 작성해 의존성을 찾고 가져와야 한다
- Spring은 EJB2와 다르게 컨테이너가 Bean의 life cycle과 프로젝트별 설정을 관리한다. 애플리케이션 코드로 객체를 관리하지 않는다. 이것을 IoC (Inversion of Control) 이라고 한다.
- AOP (Aspect Oriented Programming) 지원
- Spring은 AOP를 지원한다. Cross-Cutting하여 관심사를 모듈화할 수 있다.
- 분리된 관심사를 가로질러서, 합쳐서 모듈화할 수 있다는 뜻
- 이는 시스템 서비스를 비즈니스 로직에서 분리하여 코드의 가독성을 향상시키고 중복을 줄여준다
- Spring은 AOP를 지원한다. Cross-Cutting하여 관심사를 모듈화할 수 있다.
- 트랜잭션 관리
- EJB2는 복잡한 XML 설정이 필요하다
- Spring은 Java Annotation(
@Transactional
) 기반으로 간편하게 트랜잭션 관리를 할 수 있다- Spring Bean XML 설정 파일로도 사용할 수 있다
- JDBC 명령, 파일 업로드 등과 같은 보일러플레이트 코드의 양을 줄인다
- 테스트하기 쉽다
- EJB2에서는 테스트를 할 때 EJB 컨테이너가 필요하다
- 반면, Spring은 단위 테스트 및 통합 테스트를 위한 간단한 테스트 환경을 제공하여 개발자가 테스트를 보다 쉽게 할 수 있다
- MVC 프레임워크로 사용 가능
- EJB2는 MVC 아키텍처의 Model(비즈니스 로직)을 구현하는 데 사용할 수 있으나, View와 Controller는 다른 기술을 사용하여 구현해야 한다
- Servlet, JSP (Java Server Pages) 등
- Spring은 Spring MVC로 MVC 아키텍처를 구현하여 Web Application을 개발할 수 있다. Web Service 뿐만 아니라.
- Web Application: Web에 접속하는 End User용 프로그램
- Web Service: 네트워크 상에서 다른 컴퓨터들이 통신하는 프로그램
- RESTful한 규약으로 XML/JSON 응답을 반환하는 웹 서버 프로그램
- EJB2는 MVC 아키텍처의 Model(비즈니스 로직)을 구현하는 데 사용할 수 있으나, View와 Controller는 다른 기술을 사용하여 구현해야 한다
- 다양한 기술 스택에서 발생하는 Checked Exception을 Unchecked Exception 형식으로 변환
- JDBC, Hibernate 등 다양한 기술 스택에서 발생하는 예외를 Spring이 제공하는 표준화된 방식으로 처리할 수 있게 한다
- 필수적으로 확인해야 하는 예외를 Unchecked Exception으로 변환하는 이유는 복구 가능성이 거의 없는 예외를 위해 코드에 try catch가 반복되는 것을 막기 위해서이다
SQLException
는 거의 복구가 불가능하기 때문에catch
를 해도 수행할 작업이 없다. 따라서 런타임 에러가 발생하면 자동으로 로그를 남기고 메일 등으로 개발자에게 발생을 알리도록 처리하는 것이 최선이다.
- EJB2는 이런 예외 변환 기능이 내장되어 있지 않아 예외 처리 로직이 더 복잡하고 기술에 종속적이다
경량 컨테이너
컨테이너 (Container)
- 컨테이너는 애플리케이션의 컴포넌트를 관리하고 실행하는 환경을 제공한다
- 객체의 생명 주기를 관리하고 의존성 주입을 수행한다
- 컴포넌트의 라이프사이클을 관리하며, 필요할 때 컴포넌트를 생성하고 소멸시킨다
Spring 경량 컨테이너 (Lightweight Container)
- 가볍고 빠르게 실행될 수 있는 컨테이너
- Spring의 경량 컨테이너는 애플리케이션의 컴포넌트를 관리하는 데 필요한 최소한의 기능만을 제공하여 가볍고 빠르게 동작할 수 있다.
- EJB2는 복잡한 스펙을 따르고 있어서 개발 및 배포 과정이 번거롭고 무겁다
- Spring은 POJO를 기반으로 하여 더 간단하고 직관적으로 개발할 수 있다
- 컨테이너가 객체의 생성, 초기화, 의존성 주입 등을 관리한다. 개발자가 직접 이를 처리할 필요가 없어 개발 생산성이 높다.
- 개념: IoC (Inversion of Control)
- Spring 기능: 컴포넌트 스캔
- Annotation(
@Component
)를 사용하여 컴포넌트를 자동으로 스캔하고 등록한다
- Annotation(
- EJB2는 개발자가 명시적으로 JNDI lookup을 통해 의존성을 주입해야 한다
트랜잭션 관리
- 선언적 트랜잭션 관리 (Declarative Transaction Management)
@Transactional
Annotation- XML로도 가능
- 트랜잭션 관리를 간단하게 하고 비즈니스 로직에 집중할 수 있다
- EJB2는 복잡한 XML 설정이 필요한 반면, Spring은 Annotation 기반으로 간편하게 트랜잭션을 관리할 수 있다
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional
public void myTransactionalMethod() {
// 트랜잭션 내에서 수행되어야 하는 작업들
myRepository.save(entity1);
myRepository.save(entity2);
}
}
- 프로그래밍적 트랜잭션 관리 (Programmatic Transaction Management)
transactionTemplate.excute()
- 개발자가 명시적으로 트랜잭션을 시작하고 종료하는 방식
- 트랜잭션을 프로그래밍적으로 제어
- 특정 메서드나 클래스에 트랜잭션 Annotation을 사용할 수 없는 경우에 유용하다
- 외부 라이브러리나 프레임워크에 Annotation을 적용할 수 없는 경우
- 동적으로 트랜잭션을 처리해야 하는 경우 - 특정 조건에 따라 트랜잭션을 처리하거나 롤백
- 여러 개의 데이터베이스를 사용하고, 하나의 트랜잭션으로 묶어야 하는 경우
- 트랜잭션의 시작 및 종료 시점을 동적으로 결정해야 하는 경우
- (생각) DB 성능을 최적화하기 위해서 메소드 내에서 트랜잭션 없이 사용해도 되는 SQL과 트랜잭션을 사용해야 하는 SQL을 분리해야 할 때 사용해야 할 것 같다
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
public void updateUserEmailWithTransaction(final int userId, final String newEmail) {
transactionTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus transactionStatus) {
try {
// 데이터베이스 업데이트 작업 수행
jdbcTemplate.update("UPDATE users SET email = ? WHERE id = ?", newEmail, userId);
} catch (Exception e) {
// 롤백 처리
transactionStatus.setRollbackOnly();
throw e; // 롤백 후 예외를 다시 던져야 합니다.
}
return null;
}
});
}
}
Spring의 테스트가 쉬운 이유
- 테스트 환경 구축이 용이
- Spring은 경량 컨테이너를 사용하여 테스트 환경을 간단하게 구축할 수 있다
- 독립적인 테스트 환경 - 컨테이너가 테스트 환경에 필요한 Bean을 로드하고 관리하기 때문에 다른 환경에 영향을 주지 않고 테스트를 수행할 수 있다
- 빠르게 실행되기 때문에 테스트 시간이 짧다
- 통합 테스트 용이성 - 컨테이너가 애플리케이션의 모든 Bean을 연결하기 때문에 통합 테스트를 할 때 실제 환경과 유사한 환경을 구축할 수 있다
- 반면, EJB2는 무겁고 복잡한 애플리케이션 서버가 필요하다
- Spring은 경량 컨테이너를 사용하여 테스트 환경을 간단하게 구축할 수 있다
- 의존성 주입(Dependency Injection)으로 테스트용 Mock 객체를 주입할 수 있다
- EJB2는 의존성 주입이 없거나 제한적이므로 테스트용 더미 객체를 사용하기 어렵다
- POJO 기반 개발
- 환경에 종속되지 않기 때문에 원하는 레벨에서 코드를 테스트 할 수 있다
- Unit 테스팅 등 원하는 모듈만 독립적으로 테스트 가능
- EJB2는 테스트하려면 서버의 구동, 빌드, 배치 과정까지 필요하다
- 환경에 종속되지 않기 때문에 원하는 레벨에서 코드를 테스트 할 수 있다
- 테스트용 Annotation 지원
@RunWith
,@SpringBootTest
,@MockBean
등의 애노테이션을 사용하여 테스트를 쉽게 작성할 수 있다- EJB2는 테스트용 Annotation을 제공하지 않는다
- 내장형 데이터베이스 및 테스트 컨텍스트 지원
- Spring은 테스트를 위한 내장형 데이터베이스를 제공하고, 테스트 컨텍스트로 애플리케이션 컨텍스트를 로드하여 테스트를 수행할 수 있다
- ex) H2
- EJB2는 이러한 기능을 제공하지 않으며, 테스트를 위해 별도의 데이터베이스를 구축하고 관리해야 한다
- Spring은 테스트를 위한 내장형 데이터베이스를 제공하고, 테스트 컨텍스트로 애플리케이션 컨텍스트를 로드하여 테스트를 수행할 수 있다
참고 자료
'Spring Framework' 카테고리의 다른 글
[Spring][스크랩] Spring Boot Actuator, Prometheus, Grafana를 사용한 모니터링 환경 구축 (0) | 2024.04.08 |
---|---|
[Spring][Fix] Spring Boot Actuator - /info에 application 속성 나오지 않을 때 (0) | 2024.04.08 |
[Spring][스크랩] Spring Boot 공식 문서 (0) | 2024.04.08 |
[Spring][스크랩] Redis Session Storage 구현 (0) | 2024.03.28 |
[Spring] POJO(Plain Old Java Object) 기반 개발 (0) | 2024.03.23 |