[Spring] Spring의 특징 - PSA (일관된 서비스 추상화)

전윤혁·2024년 7월 25일
0

Spring

목록 보기
5/8

Spring의 특징

  1. POJO (Plain Old Java Object)
    순수 Java 생성 객체 지향
  1. IoC / DI (Inversion of Control / Dependency Injection)
    제어의 역전 / 의존성 주입
  1. AOP (Aspect Oriented Programming)
    관심 지향 프로그래밍

4. PSA (Portable Service Abstraction)
일관된 서비스 추상화


PSA (Portable Service Abstraction)

https://velog.io/@airoca/Spring-SpringSpring-Boot

이전 글에서 언급한 바와 같이, PSA는 특정 기술이나 플랫폼에 종속되지 않고, 일관된 방식으로 서비스에 접근할 수 있도록 하는 추상화 구조이다. "특정 기술에 종속되지 않는다" 라는 문맥을 보면 생각나는 스프링의 특징이 있지 않은가? 맞다! PSA는 스프링의 POJO 원칙을 철저히 따른 기능으로, 스프링의 라이브러리들은 PSA를 통해 POJO 원칙을 지키도록 추상화되어 있다.

POJO란?
https://velog.io/@airoca/Spring-Spring%EC%9D%98-%ED%8A%B9%EC%A7%95-POJO-Plain-Old-Java-Object


1. PSA의 정의

PSA(Portable Service Abstraction)의 정의를 분리하여 해석하면 PSA의 역할을 보다 쉽게 이해할 수 있다.

  • Portable은 다양한 환경이나 플랫폼에서 일관된 방식으로 기술에 접근할 수 있도록 한다는 의미이다.

  • Service는 특정 기능이나 작업을 제공하는 모듈을 의미하며, 추상화의 대상이 되는 "복잡한 기능" 이다.

  • Abstraction은 복잡한 구현 세부 사항을 감추고, 사용자에게 단순화된 인터페이스를 제공하는 것을 의미한다.

요약하면, PSA란 환경과 플랫폼에 관계 없이 일관된 방식으로(Portable) 기술(Service)에 접근할 수 있도록 하는 추상화 구조(Abstraction)라고 볼 수 있다.


2. PSA 사용 예시

개념이 와닿기 위해서는 역시 직관적인 예시가 필요한 법이다. PSA가 사용된 대표적인 예시 5가지를 살펴보자.

예시에 JPA(Spring Data JPA), JDBC, ORM, Hibernate에 대한 개념들이 포함되는데, 지금은 개념에 대한 구체적인 설명은 생략하고, 해당 요소들이 PSA와 어떻게 연관되는지를 위주로 설명한다.

1) Spring Data JPA

Spring Data JPA는 JPA(Java Persistence API)를 사용하여 데이터베이스 접근을 쉽게 할 수 있도록 추상화한 모듈이다. 이는 PSA의 개념을 사용하여 다양한 데이터베이스와 ORM 프레임워크에 대해 일관된 인터페이스를 제공한다.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

예를 들어, 데이터베이스가 MySQL에서 MariaDB로 변경되더라도, Spring Data JPA를 사용하면 데이터베이스 접근 코드의 변경 없이 동일한 기능을 수행할 수 있다. 데이터베이스 변경 시, 아래와 같이 JPA 설정만 변경하면 된다.

# MySQL 설정 예시
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret
  jpa:
    hibernate:
      ddl-auto: update

# MariaDB 설정 예시
spring:
  datasource:
    url: jdbc:mariadb://localhost:3306/mydb
    username: root
    password: secret
  jpa:
    hibernate:
      ddl-auto: update

2) JDBC

JDBC는 자바에서 데이터베이스와 연결하여 쿼리를 실행할 수 있는 API이다. Spring의 JdbcTemplate은 이러한 JDBC 작업을 추상화하여 데이터베이스 연결 및 쿼리 실행을 쉽게 할 수 있도록 한다.

@Autowired
private JdbcTemplate jdbcTemplate;

public List<User> findAllUsers() {
    return jdbcTemplate.query("SELECT * FROM USERS", new BeanPropertyRowMapper<>(User.class));
}

데이터베이스가 MySQL에서 Oracle로 변경되더라도, JdbcTemplate을 사용하면 코드를 거의 수정하지 않고도 동일한 기능을 수행할 수 있다.

# MySQL 설정 예시
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret

# Oracle 설정 예시
spring:
  datasource:
    url: jdbc:oracle:thin:@localhost:1521:orcl
    username: root
    password: secret

JPA와 JDBC의 차이?
JDBC는 개발자가 직접 SQL 쿼리를 작성하고 결과를 처리해야 하고, JPA는 객체-관계 매핑(ORM) 기술을 사용하여 데이터베이스와 객체 간의 매핑을 자동으로 처리한다. (JDBC는 세부적 제어 가능, but 코드가 복잡해진다.)
하지만 JPA는 데이터베이스와 객체를 매핑하는 기술일 뿐, 내부적으로는 데이터베이스와의 통신을 위해 JDBC를 사용한다.

3) Spring Web MVC

Spring Web MVC는 PSA(Portable Service Abstraction) 개념을 통해 서블릿 개발을 추상화하여 간편하게 만든다. 개발자는 직접 HttpServlet을 상속받고 doGet(), doPost() 메서드를 구현하지 않아도 된다.

@Controller
public class UserController {

    @GetMapping("/users")
    public String listUsers(Model model) {
        List<User> users = userService.findAllUsers();
        model.addAttribute("users", users);
        return "userList";
    }
}

위의 UserController는 Spring Web MVC의 컨트롤러로, 직접 서블릿을 작성하지 않고도 HTTP 요청을 처리할 수 있다. @GetMapping 애노테이션을 통해 URL 경로와 메서드를 매핑하고, Model 객체를 사용하여 뷰에 데이터를 전달할 수 있다.

또한, Spring Web MVC는 코드를 거의 변경하지 않고도 톰캣 외의 다른 서버 환경으로 쉽게 전환할 수 있다. 예를 들어, spring-boot-starter-web 의존성 대신 spring-boot-starter-webflux 의존성으로 변경하면, 톰캣 대신 Netty 기반으로 애플리케이션을 실행할 수 있다.

// 톰캣 사용
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

// Netty 사용
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'io.projectreactor.netty:reactor-netty'
}

4) Transaction

기본적으로, Low-Level로 트랜잭션을 수행하기 위해서는 setAutoCommit(), commit(), rollback()을 명시적으로 호출해야 한다. 그러나 스프링에서는 단순히 메소드에 @Transactional 어노테이션을 붙이는 것 만으로 트랜잭션 처리가 가능하다. 아래의 예시를 보자.

@Service
public class UserService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void createUser(String username, String email) {
        jdbcTemplate.update("INSERT INTO users (username, email) VALUES (?, ?)", username, email);
        // 데이터베이스 연산
    }
}

위의 예시는 JDBC 사용 시 트랜잭션의 예시이다. JPA 사용 시에도 단순히 아래와 같이 @Transactional 어노테이션을 붙이면 될 뿐이다.

@Service
public class UserService {

    @Autowired
    private EntityManager entityManager;

    @Transactional
    public void createUser(String username, String email) {
        User user = new User();
        user.setUsername(username);
        user.setEmail(email);
        entityManager.persist(user);
        // 데이터베이스 연산
    }
}

어떻게 단일 어노테이션만으로 트랜잭션 처리가 가능한 것일까? JDBC의 경우 DataSource를 통해 Connection 객체를 직접 관리하지만, JPA의 경우 EntityManager, Hibernate의 경우 Session으로 Connection을 관리한다. 즉, @Transactional은 TransactionManager를 각각 구현하고 있는 것이 아니다.

위의 구조를 보면, PlatformTransactionManager는 Spring의 트랜잭션 관리를 추상화한 인터페이스이다. 다양한 트랜잭션 관리 방식(JDBC, JTA, Hibernate 등)에 대한 공통의 방법을 정의하고, 구체적인 트랜잭션 관리 방식은 이 인터페이스를 구현하여 제공된다. (JpaTransactionManager도 존재) 그 과정을 요약하면 아래와 같다.

  1. 각 트랜잭션 매니저(DataSourceTransactionManager, JpaTransactionManager, HibernateTransactionManager)는 설정 클래스에서 빈으로 정의되며, 설정 클래스에서 DataSource, EntityManagerFactory, SessionFactory와 같은 의존성이 설정된다.

  2. @Transactional 어노테이션을 사용하여 서비스 클래스의 메서드에 트랜잭션 경계를 지정한다. Spring은 @Transactional 어노테이션을 처리하여 적절한 트랜잭션 매니저를 사용해 트랜잭션을 관리한다.

  3. Spring의 DI 메커니즘을 통해 트랜잭션 매니저가 PlatformTransactionManager에 주입된다. Spring은 설정 클래스에서 정의된 트랜잭션 매니저 빈을 자동으로 인식하고 주입한다.


5) Cache

@Cacheable, @CachePut, @CacheEvict 어노테이션을 사용하여 캐시 기능을 활용할 때도 다양한 구현체를 사용할 수 있고, 트랜잭션 관리에서 PlatformTransactionManager 인터페이스를 사용하듯이, 캐시 관리에서는 CacheManager 인터페이스를 사용한다.

트랜잭션 관리에서처럼, 캐시 관리에서 또한 ConcurrentMapCacheManager, EhCacheCacheManager, RedisCacheManager 등 다양한 구현체를 사용할 수 있다. 이 또한 DI를 통한 빈 주입이 이루어진다.


마치며

지금까지 Spring Framework의 특징을 크게 네 가지로 나누어 알아보았다. 개인적으로 각 특징을 이해할 때마다 프레임워크의 큰 틀이 점점 명확해지는 것이 정말 잘 설계된 프레임워크라는 느낌을 받는다. 이후 스프링과 관련된 글에서는, 큰 틀을 이해하느라 놓쳤던 불편한 디테일들을 하나씩 적어볼 예정이다.

profile
전공/개발 지식 정리

0개의 댓글