SpringBoot JPA 간단 동작 흐름

개발자가 되고 싶어요·2023년 8월 28일
post-thumbnail

강의를 보던 중에 @PostConstruct로 초기 데이터를 넣는 것을 보고 @PostConstruct가 언제 실행되는건지 궁금해져 스프링 부트의 전체적인 동작 흐름이 궁금해져서 찾아보게 되었다.

프로젝트로 장고만 만지다가 스프링 공부를 제대로 시작하게 되었는데
강의를 들으면서 의존성 주입이라든가 빈이라든가 기본적인 요소들이 머리에 들어오지 않았다. 이렇게 스프링 부트 흐름을 정리하니 요소들이 언제 어떻게 사용되는지 정확한 정의가 무엇인지 정리된 것 같다.


1. 스프링 부트 초기화

스프링 서버를 실행하면 SpringApplication.run() 메서드를 통해 스프링 부트 애플리케이션을 시작한다.

이때 다양한 스프링 설정들, 빈 등록, 의존성 주입 등의 작업이 이루어지는,
스프링 애플리케이션의 핵심을 구성하는 요소인 ApplicationContext가 생성된다.

또한 스프링 부트의 기본 설정과 함께, JPA 관련 설정도 로드된다.


2. 엔티티 매니저 & 데이터소스 설정

스프링 부트는 application.propertiesapplication.yml 파일에 지정된 데이터베이스 연결 정보를 기반으로 데이터소스와 JPA의 EntityManagerFactory를 생성한다.


3. 빈 등록

@SpringBootApplication 어노테이션은 기본적으로 현재 패키지와 그 하위 패키지들에 @ComponentScan을 수행한다. 따라서, 특정 어노테이션들 (@Entity, @Component, @Service, @Repository, @Controller 등)이 붙은 클래스들은 스프링 컨테이너에 빈 혹은 엔티티로 등록된다. EntityManager도 여러 부분에서 필요로 하는 곳에 주입하기 위해 빈으로 등록된다.

Spring Bean 이란?

스프링 컨테이너에 의해 관리되는 객체를 의미한다.
스프링 빈은 스프링의 Inversion of Control (IoC) 컨테이너에 
의해 생성, 조립, 관리되는 객체이다.

4. 의존성 주입 (DI)

스프링 컨테이너는 빈들 간의 의존 관계를 @Autowired, @Inject 등의 어노테이션 또는 생성자를 통해 자동으로 주입한다. lombok의 @RequiredArgsConstructor를 사용하면 필요한 생성자를 자동으로 만들며, 이 생성자를 통해 JPA의 EntityManager 등의 의존성도 주입받을 수 있다.


5. 빈 사용

응용 프로그램 코드에서는 스프링 컨테이너에 등록된 빈과 JPA의 엔티티 매니저 등을 사용하여 로직을 수행한다.


6. 트랜잭션 관리

스프링 부트와 JPA는 @Transactional 어노테이션을 통해 선언적 트랜잭션 관리를 지원한다. 이를 통해 데이터베이스 작업을 안전하게 수행할 수 있다.

스프링의 @Transactional 어노테이션을 사용하면, 선언적 트랜잭션 관리를 할 수 있다. 이는 코드 상에서 직접 트랜잭션의 시작, 종료, 롤백 등을 관리하는 것이 아니라, 스프링 프레임워크가 해당 작업들을 대신 처리하게 된다.

또한 트랜잭션 범위 내에서 수행되는 모든 데이터베이스 작업들은 예외 발생 시 롤백되어 이전 상태로 돌아간다. 이렇게 함으로써 데이터의 일관성과 무결성이 보장된다.

@Service
public class MyService {

    @Autowired
    private MyRepository repository;

    @Transactional
    public void saveThenThrowException(MyEntity entity) {
        repository.save(entity);  // DB에 데이터 저장
        throw new RuntimeException("Some error occurred");  // 예외 발생
    }
}

repository.save(entity);로 인해 데이터가 데이터베이스에 저장되려고 시도한다.
그러나 바로 이후에 예외가 발생하므로, @Transactional에 의해 그 동안의
모든 데이터베이스 변경 작업이 롤백되어, 실제로 데이터베이스에는 아무런 변경이 발생하지 않게 된다.

@Transsactional을 명시 하지 않는다면?

flush()commit()을 명시적으로 호출해야 변경 사항이 데이터베이스에 반영된다.

EntityManager em = ...; // 엔티티 매니저 획득
em.persist(someEntity); // 엔티티 저장
em.flush(); // 영속성 컨텍스트의 변경 내용을 데이터베이스에 즉시 반영

@Transactional을 사용하여 선언적 트랜잭션 관리를 활용하는 것이 더 안전하고 효율적이다. 이렇게하면 트랜잭션의 경계에서 자동으로 커밋 및 롤백을 관리할 수 있다.


7. 빈 생명주기

스프링 컨테이너는 빈의 생명 주기를 관리하며, 빈 생성 후 초기화 작업이 필요할 경우 @PostConstruct를, 종료 전에 정리 작업이 필요할 경우 @PreDestroy를 사용한다.

profile
I want to be a Backend Developer (run start-up)

0개의 댓글