Spring Framework

[Spring] Spring의 장점 (EJB2와 비교)

개발자 이우진 2024. 3. 25. 17:16

개요

Spring은 로드 존슨이 당시 주류였던 EJB2의 단점을 보완하여 개발하였다. Spring은 Jakarta EE 개발을 더 쉽게 만드는 것을 목표로 한다. Sping의 장점은 다음과 같다.

  1. 가볍다 (Lightweight)
    • EJB2는 무겁고 복잡한 구조를 가지고 있었다
    • Spring은 경량 컨테이너를 사용하여 구동 속도가 훨씬 가볍고 더 빠르다
  2. POJO 기반 프로그래밍 (Plain Java Old Object)
    • EJB2는 특정 인터페이스를 구현해야 하는 등 많은 제약이 있었다
    • Spring은 POJO를 사용하여 더 간단하고 객체지향적으로 개발할 수 있다
  3. 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) 이라고 한다.
  4. AOP (Aspect Oriented Programming) 지원
    • Spring은 AOP를 지원한다. Cross-Cutting하여 관심사를 모듈화할 수 있다.
      • 분리된 관심사를 가로질러서, 합쳐서 모듈화할 수 있다는 뜻
    • 이는 시스템 서비스를 비즈니스 로직에서 분리하여 코드의 가독성을 향상시키고 중복을 줄여준다
  5. 트랜잭션 관리
    • EJB2는 복잡한 XML 설정이 필요하다
    • Spring은 Java Annotation(@Transactional) 기반으로 간편하게 트랜잭션 관리를 할 수 있다
      • Spring Bean XML 설정 파일로도 사용할 수 있다
      • JDBC 명령, 파일 업로드 등과 같은 보일러플레이트 코드의 양을 줄인다
  6. 테스트하기 쉽다
    • EJB2에서는 테스트를 할 때 EJB 컨테이너가 필요하다
    • 반면, Spring은 단위 테스트 및 통합 테스트를 위한 간단한 테스트 환경을 제공하여 개발자가 테스트를 보다 쉽게 할 수 있다
  7. 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 응답을 반환하는 웹 서버 프로그램
  8. 다양한 기술 스택에서 발생하는 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)를 사용하여 컴포넌트를 자동으로 스캔하고 등록한다
    • 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의 테스트가 쉬운 이유

  1. 테스트 환경 구축이 용이
    • Spring은 경량 컨테이너를 사용하여 테스트 환경을 간단하게 구축할 수 있다
      • 독립적인 테스트 환경 - 컨테이너가 테스트 환경에 필요한 Bean을 로드하고 관리하기 때문에 다른 환경에 영향을 주지 않고 테스트를 수행할 수 있다
      • 빠르게 실행되기 때문에 테스트 시간이 짧다
      • 통합 테스트 용이성 - 컨테이너가 애플리케이션의 모든 Bean을 연결하기 때문에 통합 테스트를 할 때 실제 환경과 유사한 환경을 구축할 수 있다
      • 반면, EJB2는 무겁고 복잡한 애플리케이션 서버가 필요하다
  2. 의존성 주입(Dependency Injection)으로 테스트용 Mock 객체를 주입할 수 있다
    • EJB2는 의존성 주입이 없거나 제한적이므로 테스트용 더미 객체를 사용하기 어렵다
  3. POJO 기반 개발
    • 환경에 종속되지 않기 때문에 원하는 레벨에서 코드를 테스트 할 수 있다
      • Unit 테스팅 등 원하는 모듈만 독립적으로 테스트 가능
    • EJB2는 테스트하려면 서버의 구동, 빌드, 배치 과정까지 필요하다
  4. 테스트용 Annotation 지원
    • @RunWith, @SpringBootTest, @MockBean 등의 애노테이션을 사용하여 테스트를 쉽게 작성할 수 있다
    • EJB2는 테스트용 Annotation을 제공하지 않는다
  5. 내장형 데이터베이스 및 테스트 컨텍스트 지원
    • Spring은 테스트를 위한 내장형 데이터베이스를 제공하고, 테스트 컨텍스트로 애플리케이션 컨텍스트를 로드하여 테스트를 수행할 수 있다
      • ex) H2
    • EJB2는 이러한 기능을 제공하지 않으며, 테스트를 위해 별도의 데이터베이스를 구축하고 관리해야 한다

참고 자료