개발기술/Spring

스프링부트 전체구조

bsh6226 2024. 7. 24. 10:35

 

스프링 전체흐름

1. Server Startup:

  • When you start your Spring Boot application (or deploy it to a servlet container like Tomcat), the server begins its initialization process.

2. Spring Boot Application Initialization:

  • SpringApplication.run(): This method is called in your main() method, which starts the entire Spring application.
  • Spring Boot Auto-Configuration: Spring Boot auto-configures the application context based on the classpath settings, other beans, and various property settings.

3. WebApplicationContext Initialization:

  • WebApplicationContext Creation: A specialized version of ApplicationContext, the WebApplicationContext is created if your application is a web application.
    • All configurations, whether they pertain to security, MVC, data, or any other aspect, are ultimately registered within this WebApplicationContext.
  • Bean Definitions Loading: During this phase, Spring scans your application for bean definitions (components, services, repositories, controllers, and configuration classes).
  • Security Configuration: As part of the bean initialization process, security configurations defined in classes annotated with @EnableWebSecurity or @Configuration are also loaded and processed.
  • Filter Chain Setup: As part of the Security Configuration, Spring sets up a chain of security filters 

4. DispatcherServlet Initialization:

  • DispatcherServlet Bean Creation: The DispatcherServlet is a special Servlet in Spring that acts as the front controller, handling all incoming HTTP requests.
  • Mapping to URL Patterns: The DispatcherServlet is typically mapped to the "/" URL pattern, meaning it handles all requests coming to the application.
  • Loading Handler Mappings and Other Beans: The DispatcherServlet loads handler mappings, view resolvers, and other necessary components from the WebApplicationContext.

5. Request Handling:

  • Server Receives HTTP Request: When a client sends an HTTP request, the server receives it and passes it to the DispatcherServlet.
  • Filter Chain Execution: Before the request reaches the DispatcherServlet, it passes through the filter chain configured during the Security Configuration phase.
  • DispatcherServlet Processing: After passing through the filters, the request reaches the DispatcherServlet.

 

 

 

 

스프링 MVC - 필터, 인터셉트

 

 

 

 

개념설명

웹상에서 흐르는 데이터에 공통적인 처리를 할때 필요한 것이 필터와 인터셉트이다.

 

필터 

  • 스프링 외부의 서블릿에서 제공하는 공통처리기능, dispatcher로 가기전의 client의 불필요한 request(해킹 등)를 걸러주는 역할
  • 스프링 내 요청이 들어오기 전과 스프링 요청이 나갈때 처리가능
  • 조금더 low-level 처리가 가능

인터셉터

  • 스프링에서 제공하는 공통처리 기능
  • dispatcher에서 handler mapping이 완료된 후 controller로 향하는 데이터와 controller로부터 나오는 데이터가 특정조건에 만족한다면, 특정처리가 가능하다. 하여, 실제 매핑된 Handler 정보 확인가능(어떤 것이 실제 내 요청을 처리하는지도 확인 가능)
  • 조금 더 상세한 조건식과 세부적인 스펙(pre, post, after)를 통해서 구체적인 시점에 구체적인 동작가능
  • AOP와 비교한다면  AOP는 좀더 java code( 패키지, annotation, method명 등)에 대한 처리를, 인터셉터와 필터는 web관련 조건에 따라(url주소 protocol 등)처리를 한다는 점에서 차이가 있다.
  • AOP는 인터셉터보다 더 구체적인 조건 (애노테이션, 파라미터, 주소 등)과 동작위치 (afterThrowing 등)을 갖음

 

사용설명

필터사용 - filter은 서블릿 기능으로 스프링과 무관하게 동작할 수도 있지만 스프링 빈으로 등록할시 여러가지 이점이 있음. 그러므로 component로 등록한다. filter라는 인터페이스를 구현하여 자체적으로 클래스를 만들고 dofilter를 정의하여 필터링 기능을 생성한다.

 

필터셋등록 - 그리고 filter는 보통 복수의 필터가 있기에 , configuration이라는 별도의 class를 만들고 registerfilter라는 메소드를 생성 하고 반환타입으로 filterregisterationbean이라는 set형식으로 filter들을 set에 등록하게 끔 한다. filterregisterationbean으로 필터가 동작할 url이나 필터의 순서를 지정가능함.

 

인터셉트는 handlerintercept라는 인터페이스를 구현하여 만들고  prehandle(handler처리전) posthandle(hadler응답성공후) aftercompletion( handler응답성공무관,항상). 각 메소드 들은 parameter로 request, response, handler, modelandview 등을 갖는다. 각각 return true를 해주면 method들이 순서대로 실행된다. 인터셉터는 조금더 다양한 정보로, 구체적인 정보로 동작은 해줄 수 있음. filter은 요즘 잘 안쓰면서 인터셉트가 더 잘쓰이는 추세인것같음.

 

인터셉트를 등록하기 위해서는 WebMvcConfigurer라는 인터페이스를 구현하면 편리하게 등록할 수 있다. filter를 담고있는 configuration클래스를 구현체로 사용해서 addinterceptors 메소드를 구현하여 인터셉터의 순서, 포함할 url, 제외할 url등을 설정하면된다. WebMvcConfigurer의 메소드들은 자동적으로 bean으로 등록되도록 구현되어있다. ( 필터의 경우 spring mvc가아닌 서블릿의 개체이기때문에 별도로 서블릿으로부터 filterregisterationbean을 끌어와서 구현한 것임. )

 

 

 

 

CleanArchitecture : Division of Layer

Client:

  • 프론트엔드 모듈을 의미하며, 사용자 인터페이스를 통해 서버와 상호작용합니다.
  • 사용자가 입력한 데이터를 서버로 보내고, 서버로부터 받은 데이터를 화면에 표시합니다.

DTO (Data Transfer Object):

  • 계층 간 데이터 교환을 위한 객체입니다.
  • 주로 클라이언트에서 서버까지 데이터를 전달할 때 사용됩니다.
  • DTO는 범용으로 쓰지 않고 개별적인 용도로 써야 오류가 나지 않는다. 메소드의 필요에 따라 1:1로 만들것. (Controller DTO는 Controller에서만, Service DTO는 Service에서만)
  • Service DTO는 Entity에서 일부 데이터를 추출하여 Web Layer에서 필요로 할만한  데이터 전송에 최적화된 형태로 설계된다.
    • 반면 Request DTO는 Web의 요구에 따라서 변경이 잦으므로, Service Layer에 침투되지 않도록 분리한다. 필요시에 Service DTO로 변환하여 전달한다.

Controller:

  • 클라이언트로부터 HTTP 요청을 받아들이는 역할을 합니다.
  • 요청을 적절한 서비스 계층으로 전달하고, 서비스로부터 받은 결과를 클라이언트에 반환합니다.
  • 주로 @Controller나 @RestController 애노테이션을 사용하여 정의합니다.
  • 예외처리 : 우선, Contoller별로 custon excpetion Handler로 1차 처리 후, Global Handler을 통해서 전체 예외처리

Service:

  • 비즈니스 로직을 처리하는 계층입니다.
  • Controller로부터 받은 DTO를 사용하여 필요한 로직을 수행하고, 이를 사용하여 Entity를 생성하거나 업데이트합니다. 로직이 다 수행되었다면 Controller에 응답을 위해서 return값을 설정하고 주로 동일한 DTO를 쓴다.
  • 주로 @Service 애노테이션을 사용하여 정의합니다.
  • 예외처리 : 비즈니스 로직은 예외처리까지 포함하는 범위이며 로직의 원자성을 위해서 excpetion은 Service 내에서만 발생하도록 하는 것이 best practice.

Entity (Domain):

  • DB의 테이블과 1:1로 대응되는 객체입니다.
  • 테이블의 컬럼과 엔티티의 필드가 매핑되며, 여러 엔티티 간의 연관관계(관계형 데이터베이스의 외래키 등)를 정의합니다.
  • 주로 @Entity 애노테이션을 사용하여 정의합니다.

Repository:

  • DB와 직접 연결되어 CRUD(Create, Read, Update, Delete) 작업을 수행하는 계층입니다.
  • Entity에 접근하기 위한 메서드들을 정의하며, Spring Data JPA의 경우 JpaRepository 인터페이스를 상속받아 구현합니다.
  • 주로 @Repository 애노테이션을 사용하여 정의합니다.

DAO (Data Access Object):

  • 데이터베이스에 접근하는 객체로, 퍼시스턴스 계층이라고도 불립니다.
  • 서비스 계층이 DB와 통신할 수 있도록 도와줍니다.
  • Spring Data JPA를 사용할 경우, Repository가 DAO의 역할을 합니다.

ServiceImpl, DAOImpl:

  • 서비스와 DAO는 인터페이스로 정의되며, 실제 구현 클래스는 Impl 접미사를 붙여서 구현합니다.
  • 인터페이스를 통해 의존성을 주입받아 테스트 용이성과 코드의 유연성을 높입니다.

 

 

Design Concern

  • Seperation between the database architecture(Db Interaction,Entity) from the API(User Interaction, DTO)
    • 1. Performance Concerns :
      • lazy-loaded
    • 2. Transactional Concerns :
      • where lazy loading triggers outside of transactional boundaries, causing exceptions like LazyInitializationException.
    • 3. Data Safety :
      • If entities are exposed directly, any modifications made to the returned entities could inadvertently affect the database once the transaction commits.
      • + sensitive info in Entity
    • 4. Division of work
      • API와 DB에서 요구하는 데이터가 상이할 수 있다. API의 요구에 따라서 ENtity를 수정하는 것은, DB에 영향을 주기에 불가능하고 API요구에 맞도록 DTO를 별도로 만들어주는 것이 올바른 접근이다. 혹시 API의 요구사항 변경이 생겼을때 더욱 유연하게 대응할 수 있음. 
      • API Stability vs. Database Changes: . Using DTOs allows the database model to evolve without necessarily impacting the API.
    • Entity에서 DTO로 넘겨보내기 위해서 DTO 내부구조를 아래와 같이 entity에서 정보를 뽑아서 DTO를 생성하도록 주로함.
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AccountDto {
    private Long userId;
    private String accountNumber;
    private Long balance;

    private LocalDateTime registeredAt;
    private LocalDateTime unregisteredAt;

    public static AccountDto fromEntity(Account account) {
        return AccountDto.builder().
                userId(account.getAccountUser().getId())
                .accountNumber(account.getAccountNumber())
                .balance(account.getBalance())
                .registeredAt(account.getRegisteredAt())
                .unregisteredAt(account.getUnregisteredAt()).
                build();