반응형

스프링 프레임워크에서 객체 의존성을 관리하기 위해 주로 사용되는 세 가지 어노테이션인 @Autowired, @Resource, 그리고 @Inject에 대해 설명하고, 각각의 특징과 차이점을 비교해 드리겠습니다. 이 어노테이션들은 모두 의존성 주입(Dependency Injection, DI)을 수행하는 데 사용되며, 스프링 애플리케이션에서 중요한 역할을 합니다.

 


의존성 주입이란

의존성 주입(Dependency Injection, DI)은 소프트웨어 엔지니어링에서 사용되는 디자인 패턴 중 하나로, 객체가 자신의 의존성(즉, 다른 객체들)을 직접 생성하거나 검색하지 않고, 외부에서 받도록 하는 기술입니다. 이 패턴을 사용하면 컴포넌트 간의 결합도가 낮아지고, 유연성이 향상되며, 코드의 재사용성과 테스트 용이성이 증가합니다.

 

의존성 주입 어노테이션

1. @Autowired (Spring Framework)

 

라이브러리: Spring Framework

기능: 타입에 기반하여 자동으로 의존성을 주입합니다. 만약 타입이 일치하는 빈이 여러 개 있는 경우, 필드 이름이나 파라미터 이름으로 빈을 구별하여 주입합니다.

주입 방법: 필드, 세터, 생성자 주입이 가능하며, 생성자 주입이 권장됩니다.

특징: @Autowired는 스프링의 기본 설정에서 자동으로 사용될 수 있으며, required 속성을 통해 의존성이 필수적인지 선택적인지 지정할 수 있습니다.

 

2. @Resource (Java Standard)

 

라이브러리: JSR-250, Java Standard

기능: 주로 이름에 기반하여 의존성을 주입합니다. 이름을 명시하지 않으면 필드의 이름 또는 세터 메서드의 이름을 사용합니다. 이름으로 적합한 빈을 찾지 못하면 타입에 의해 주입을 시도합니다.

주입 방법: 필드 및 세터 메서드에 사용될 수 있습니다.

특징: @Resource는 Java EE에서 제공되며, 스프링과 같은 DI 컨테이너에서도 사용할 수 있습니다. 스프링에서는 @Autowired보다는 약간 더 명시적인 의존성 주입 방식을 제공합니다.

 

3. @Inject (Java Dependency Injection)

 

라이브러리: JSR-330, Java Dependency Injection standard

기능: 타입에 기반하여 의존성을 주입합니다. @Autowired와 유사하게 작동하지만, required 속성이 없습니다.

주입 방법: 필드, 세터, 생성자 주입이 가능하며, 역시 생성자 주입이 권장됩니다.

특징: @Inject는 Java의 표준 의존성 주입 규약을 따르며, 스프링 뿐만 아니라 다른 DI 프레임워크에서도 사용될 수 있습니다. 스프링에서는 @Autowired와 거의 동일하게 작동하지만, 스프링 특유의 기능인 required 속성을 지원하지 않습니다.

 

비교

 

유연성 및 호환성: @Inject@Resource는 Java 표준을 따르므로, 다른 Java 기반 프레임워크로의 이동성이 더 높습니다. 반면, @Autowired는 스프링에 종속적입니다.

기능성: @Autowiredrequired 속성을 통해 의존성이 필수인지 여부를 설정할 수 있어 더 많은 유연성을 제공합니다. @Inject는 이러한 속성이 없습니다.

사용의 용이성: @Autowired는 스프링 프레임워크에서 가장 일반적으로 사용되며, 스프링 특화 기능

 

 

위의 키워드 로 의존성 주입을 구현하는 방법

의존성 주입의 구현 방법

1. 생성자 주입: 객체를 생성할 때 생성자를 통해 의존성을 전달합니다. 이 방법이 가장 권장되는 방식으로, 객체의 불변성을 보장할 수 있습니다.

2. 세터 주입: 객체 생성 후 세터 메서드를 통해 의존성을 주입합니다. 생성자 주입에 비해 유연성은 높지만, 객체의 완전성을 보장받기 어려울 수 있습니다.

3. 필드 주입: 리플렉션을 사용하여 직접 필드에 의존성을 주입합니다. 코드는 간결해지지만, 다른 주입 방식에 비해 많은 단점을 가지고 있으며 권장되지 않습니다.

 

1. 생성자 주입(Constructor Injection)

 

생성자 주입은 가장 권장되는 방식입니다. 객체가 생성될 때 모든 의존성이 완전히 주입되기 때문에, 객체가 일관된 상태를 유지할 수 있습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // UserService의 메서드
}

 

2. 세터 주입(Setter Injection)

 

세터 주입은 선택적 의존성이 필요할 때 유용할 수 있습니다. 이 방법을 사용하면 객체 생성 후 필요에 따라 의존성을 설정할 수 있습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // UserService의 메서드
}

 

3. 필드 주입(Field Injection)

필드 주입은 코드는 간결하지만, 많은 단점을 가지고 있습니다. 특히, 테스트가 어렵고 순환 참조 문제가 발생할 수 있습니다. 따라서 권장되지 않는 방법입니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    // UserService의 메서드
}

 

 

생성자 주입을 간단하게 해주는 어노테이션

@RequiredArgsConstructor는 Lombok 라이브러리의 주요 어노테이션 중 하나입니다. 이 어노테이션은 자바 클래스에 대해 필요한 생성자를 자동으로 생성해 주는 기능을 제공합니다. 사용하게 되면, 명시적으로 생성자를 작성하지 않아도 되므로 코드의 간결성을 유지할 수 있습니다.

 

@RequiredArgsConstructor의 작동 방식

 

@RequiredArgsConstructor 어노테이션이 적용된 클래스는 모든 final 필드와 @NonNull 어노테이션이 붙은 필드에 대한 생성자를 자동으로 생성합니다. 이 생성자는 해당 필드들을 초기화하는 역할을 하므로, 객체가 올바르게 구성되도록 보장합니다.

 

주요 특징

 

자동 생성자 생성: 클래스의 final 필드 또는 @NonNull이 붙은 필드에 대한 생성자를 자동으로 생성합니다.

코드의 간결성 증가: 생성자를 직접 작성하지 않아도 되므로, 코드를 더 간결하게 유지할 수 있습니다.

객체 불변성 지원: final 필드에 대한 생성자를 자동으로 생성하기 때문에 불변 객체를 만드는 데 유용합니다.

Null 안정성 강화: @NonNull 어노테이션이 붙은 필드는 생성자에서 null 검사 로직을 자동으로 추가하여, 객체 생성 시 null이 되지 않도록 강제합니다.

 

import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class User {
    private final String name;
    private final int age;
    @NonNull
    private String email;

    // Lombok이 자동으로 다음 생성자를 생성해줍니다.
    // public User(String name, int age, String email) {
    //     this.name = name;
    //     this.age = age;
    //     this.email = Objects.requireNonNull(email, "email is required");
    // }
}
반응형
반응형

 

웹사이트 접속:

JetBrains의 공식 웹사이트에 접속합니다. JetBrains 공식 웹사이트 링크를 클릭하거나 웹 브라우저에서 “IntelliJ IDEA download”로 검색하여 접근할 수 있습니다.

3. Community Edition 및 Ultimate 다운:

 두 버젼 차이 

Community Edition은 JVM 언어로 작업하는 개인 개발자나 학생들에게 적합한 반면, Ultimate Edition은 다양한 프로그래밍 언어와 웹 개발, 데이터베이스 관리, 서버 관리 등 복잡한 기업용 애플리케이션을 개발해야 하는 전문 개발자나 기업에 적합한 버전입니다. 이를 통해 개발 환경의 요구 사항과 예산에 맞는 적절한 버전을 선택할 수 있습니다.


2. 
운영 체제 선택:

 다운로드 페이지에서 사용 중인 운영 체제에 맞는 버전을 선택합니다. Windows, macOS, Linux 중에서 선택할 수 있습니다.

 

윈도우 

https://www.jetbrains.com/idea/download/?section=windows#section=windows

 

Download IntelliJ IDEA – The Leading Java and Kotlin IDE

Download the latest version of IntelliJ IDEA for Windows, macOS or Linux.

www.jetbrains.com

mac 

https://www.jetbrains.com/idea/download/?section=mac#section=mac

 

Download IntelliJ IDEA – The Leading Java and Kotlin IDE

Download the latest version of IntelliJ IDEA for Windows, macOS or Linux.

www.jetbrains.com

 

intelliJ IDEA에서 새 프로젝트 생성하기

 

1. IntelliJ IDEA 실행:

IntelliJ IDEA를 실행합니다. 이미 열린 프로젝트가 있다면, File 메뉴에서 Close Project를 선택하여 현재 프로젝트를 닫습니다.

2. 새 프로젝트 시작:

시작 화면에서 New Project를 선택하거나, File 메뉴에서 New -> Project...를 선택합니다.

3. 프로젝트 유형 선택:

왼쪽 패널에서 Java를 선택합니다. (IntelliJ IDEA Ultimate Edition을 사용하는 경우 다른 프로그래밍 언어나 프레임워크를 선택할 수 있습니다.)

프로젝트 SDK를 설정합니다. SDK가 설정되어 있지 않은 경우, Add SDK를 클릭하여 JDK를 설치하거나 기존에 설치된 JDK를 선택합니다.

 

5. 프로젝트 정보 입력:

Next 버튼을 클릭한 다음, 프로젝트의 이름과 저장 위치를 입력합니다.

Project name: 프로젝트의 이름을 입력합니다.

Project location: 프로젝트 파일을 저장할 위치를 지정합니다.

 

6. 프로젝트 생성 완료:

모든 설정을 마쳤다면 Finish 버튼을 클릭하여 새 프로젝트를 생성합니다.

IntelliJ IDEA가 새 프로젝트를 설정하고 초기화하는 과정을 진행합니다.

 

7. 프로젝트 구조 확인:

프로젝트가 생성된 후, 프로젝트 디렉토리 구조를 확인할 수 있습니다. 일반적으로 src 폴더가 생성되며, 여기에 소스 코드 파일을 추가할 수 있습니다.

 

이제 IntelliJ IDEA에서 새로운 프로젝트를 생성하고 기본 설정을 완료했습니다. 이 프로젝트를 기반으로 Java 코드를 작성하고 개발을 진행할 수 있습니다. 프로젝트 설정을 변경하거나 추가 구성이 필요한 경우, File 메뉴에서 Project Structure를 선택하여 다양한 프로젝트 설정을 조정할 수 있습니다.

 

우측 상단에 실행버튼으로 부트 로컬 실행

 

반응형
반응형

 

Pageable

Pagination 기능을 편리하게 사용할 수 있도록 JPA는 Pageable이라는 객체를 제공한다.

 

 

controller 에서 부터 pageable 관련 파라미터를 받을 수 있다. 

정렬 기능

@GetMapping("/")
public ResponseEntity getData(
              @PageableDefault(size = 10, sort = "reqDt", direction= Sort.Direction.DESC)
              Pageable pageable) 
// reqDt 에 대한 내림차순 정렬


@SortDefault 

위의 방식은 정렬을 한가지만 할 수 있어, 여러 정렬 조건을 추가하려면 @SortDefault 를 추가하면 된다. 

@GetMapping("/")
public ResponseEntity getData(
      		@SortDefault.SortDefaults({
              	@SortDefault(sort = "id", direction = Sort.Direction.ASC),
                @SortDefault(sort = "reqDt", direction = Sort.Direction.DESC)
              })
              @PageableDefault(size = 10)
              Pageable pageable) 
// id 오름차순 및 reqDt 에 대한 내림차순 정렬

 

controller 요청방법 

?page=0&size=10&sort=regDt,desc


PageRequest

다른 방법으로는 controller 에서 외에 paging 관련 데이터를 PageRequset 객체에 넣어 
Pagable 을 생성 후 find 쿼리 메소드에 객체를 전달하면 된다.

 

Pagable pageObj = PageRequest.of(0, 5, Sort.by("reqDt").descending().and(Sort.by("id")));

 

controller 에서 부터 PageRequest 를 세팅 하고 싶다면 Pageable을 대체하는 PageRequest 관련 객체를 따로 생성하면 된다.

public final class PageRequest {

    private int page;
    private int size;
    private Sort.Direction direction;

    public void setPage(int page) {
        this.page = page <= 0 ? 1 : page;
    }

    public void setSize(int size) {
        int DEFAULT_SIZE = 10;
        int MAX_SIZE = 50;
        this.size = size > MAX_SIZE ? DEFAULT_SIZE : size;
    }

    public void setDirection(Sort.Direction direction) {
        this.direction = direction;
    }
    // getter

    public org.springframework.data.domain.PageRequest of() {
        return org.springframework.data.domain.PageRequest.of(page -1, size, direction, "createdAt");
    }
 }
  • setPage(int page) 메서드를 통해서 0보다 작은 페이지를 요청했을 경우 1 페이지로 설정
  • setSize(int size) 메서드를 통해서 요청 사이즈 50 보다 크면 기본 사이즈인 10으로 바인딩
  • of() 메서드를 통해서 PageRequest 객체를 응답해줍니다. 페이지는 0부터 시작하니 page -1 합니다. 본 예제에서는 sort는 createdAt 기준으로 진행.

 


Repository

@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
    Page<Board> findAll(Pageable pageable);
}

find 객체의 리턴에 Page<객체명> 을 해주면 자동으로 count 쿼리를 jpa 가 요청하여, paging 에 필요한 데이터를 조회 후 객체에 추가해 준다. 

Pageable 에 해당 되는 size 및 page, sort 에 해당 되는 쿼리를 jpa 가 생성하여 보내준다.

 

결과가 아래와 같이 생성된다.

{
    "content": [
        {
            "id": 3,
            "name": "이름",
            "description": "설명",
            "createdAt": "2024-03-10T13:22:09",
            "updatedAt": "2024-03-10T13:22:09"
        },
        {
            "id": 2,
            "name": "이름2",
            "description": "자세한설명",
            "createdAt": "2024-03-10T13:22:09",
            "updatedAt": "2024-03-10T13:22:09"
        }
    ],
    "pageable": {
        "sort": {
            "empty": false,
            "sorted": true,
            "unsorted": false
        },
        "offset": 0,
        "pageSize": 2,
        "pageNumber": 0,
        "paged": true,
        "unpaged": false
    },
    "last": false,
    "totalPages": 3,
    "totalElements": 5,
    "size": 2,
    "number": 0,
    "sort": {
        "empty": false,
        "sorted": true,
        "unsorted": false
    },
    "first": true,
    "numberOfElements": 2,
    "empty": false
}
 

 

 

Page 객체는 totalPages 및 totalElements 값을 count 쿼리를 통해 가지고 있다.

totalCount를 얻기 위해서는 다음과 같이 getTotalElements() 메서드를 사용한다:

public interface Page<T> extends Slice<T> {
    static <T> Page<T> empty() {
        return empty(Pageable.unpaged());
    }

    static <T> Page<T> empty(Pageable pageable) {
        return new PageImpl(Collections.emptyList(), pageable, 0L);
    }

    int getTotalPages();

    long getTotalElements();

    <U> Page<U> map(Function<? super T, ? extends U> converter);
}

 

 

https://www.baeldung.com/spring-data-jpa-pagination-sorting [PageRequest 예시]

 
반응형
반응형

excel poi 라이브러리

 <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

spring webflux 에서는 HttpServletResponse 를 사용하지 않아 header 에 xlsx 정보를 넣어주는부분에서 spring 일반 샘플대로 하면 오류가 생길 것이다. 
HttpHeaders 에 set 해주고 Mono.just 에 headers 를 세팅해주면 된다. 

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import reactor.core.publisher.Mono;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

@RestController
public class ExcelController {

    @GetMapping("/download-excel")
    public Mono<ResponseEntity<ByteArrayResource>> downloadExcel() {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");

        // Create some sample data
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Name");
        headerRow.createCell(1).setCellValue("Email");

        Row dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue("John Doe");
        dataRow.createCell(1).setCellValue("john.doe@example.com");

        // Generate Excel file bytes
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            workbook.write(outputStream);
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Set up the HTTP response headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "data.xlsx");

        // Create a ByteArrayResource from the file bytes
        ByteArrayResource resource = new ByteArrayResource(outputStream.toByteArray());

        // Return the response entity with the file bytes and headers
        return Mono.just(ResponseEntity.ok()
                .headers(headers)
                .contentLength(outputStream.size())
                .body(resource));
    }
}

 

반응형
반응형

필요한 라이브러리

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
    <groupId>io.asyncer</groupId>
    <artifactId>r2dbc-mysql</artifactId>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

 

 

설정 코드 

@Configuration
@EnableR2dbcRepositories
public class R2DBCConfiguration extends AbstractR2dbcConfiguration {
    @Override
    @Bean
    public ConnectionFactory connectionFactory() {
        ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
                        .option(DRIVER, "mysql")
                        .option(HOST, "localhost")
                        .option(USER, "root")
                        .option(PASSWORD, "password")
                        .option(PORT, 3307)
                        .option(DATABASE, "db")
                                                    .build());
        return connectionFactory;
    }
}

와 같이 설정하면 db 연결된다.

세팅 및 설정 관련 문서

https://github.com/asyncer-io/r2dbc-mysql

반응형
반응형

webflux 를 사용하면 spring boot 내장서버가 tomcat 에서 netty 로 사용해야 하는데,

netty 가 비동기에 유리한 서버이다 보니, sleep 을 주고 싶은 로직이 있을 떄 sleep 을 주기가 비효율적이다

 

 

Spring Netty를 사용할 때 Thread.sleep()를 사용하여 지정된 시간 동안 스레드 실행을 일시 중지 할 수 있다 .

하지만 이벤트 루프를 차단하고 성능 문제를 일으킬 수 있으므로 Netty 애플리케이션에서 와 같은 차단 작업을 사용하는 것은 일반적으로 권장되지 않는다 .

 

대신 Netty는 패키지 에서 사용할 수 있는 ScheduledExecutorService를 사용하여 작업 지연을 위한 비동기 대안을 제공한다 io.netty.util. schedule()의 방법을 사용하여 ScheduledExecutorService지정된 지연 후 작업 실행을 예약 할 수 있습니다 .

ScheduledExecutorService 다음은 Spring Netty 애플리케이션에서 어떻게 사용할 수 있는지에 대한 예입니다

 

 

spring netty 에서 ScheduledExecutorService를 사용한 예시다.

EventLoopGroup클래스에 빈을 주입합니다 .

@Autowired
private EventLoopGroup eventLoopGroup;
 

ScheduledExecutorService지연이 있는 작업을 예약하려면 다음을 사용

 
eventLoopGroup.schedule(() -> {
    // Code to be executed after the delay
}, 500, TimeUnit.MILLISECONDS);

 

 

이 예에서 작업은 500밀리초 지연 후에 실행됩니다. 필요에 따라 지연 및 시간 단위를 조정할 수 있다.

Netty에서 제공하 ScheduledExecutorService를 사용하면 이벤트 루프를 지연시키지 않으므로 애플리케이션이 응답성과 성능을 유지할 수 있습니다.

참고: Spring Netty 애플리케이션에서 Thread.sleep()를 사용해야 하는 경우 이벤트 루프 차단을 피하기 위해 별도의 스레드에서 사용할 수 있습니다. 그러나 일반적으로 가능할 때마다 Netty에서 제공하는 비동기 메커니즘을 활용하는 것이 좋다.

 

ScheduledExecutorService는 특정 시간 또는 간격으로 작업을 예약하고 실행하는 편리한 방법을 제공하므로 주기적 또는 지연된 작업을 수행해야 하는 시나리오에 유용.
비동기 이벤트 기반 네트워크 애플리케이션 프레임워크인 Netty는 ScheduledExecutorService를 활용하여 비차단 방식으로 지연된 작업을 처리한다. 애플리케이션의 실행 및 성능을 차단하지 않고 이벤트 루프에서 작업을 예약할 수 있다.

 

 

 

반응형
반응형

@ExceptionHandler

@ExceptionHandler  @Controller , @RestController 가 적용된 Bean 에서 발생하는 예외를 잡아서 하나의 메서드에서 처리해주는 기능이다. @ExceptionHandler 에 설정한 예외가 발생하면 handler가 실행된다. 

 

@RestController
public class MyRestController {
    ...
    ...
    @ExceptionHandler(NullPointerException.class)
    public Object nullex(Exception e) {
        System.err.println(e.getClass());
        return "myService";
    }
}

위와 같이 적용하기만 하면 된다. @ExceptionHandler라는 어노테이션을 쓰고 인자로 캐치하고 싶은 예외클래스를 등록해주면 끝난다.

→ @ExceptionHandler({ Exception1.class, Exception2.class}) 이런식으로 두 개 이상 등록도 가능하다.

위의 예제에서 처럼하면 MyRestController에 해당하는 Bean에서 NullPointerException이 발생한다면, @ExceptionHandler(NullPointerException.class)가 적용된 메서드가 호출될 것이다.

 

주의사항/알아 둘 것

  • Controller, RestController에만 적용가능하다. (@Service같은 빈에서는 안됨.)
  • 리턴 타입은 자유롭게 해도 된다. (Controller내부에 있는 메서드들은 여러 타입의 response를 할 것이다. 해당 타입과 전혀다른 리턴 타입이어도 상관없다.)
  • @ExceptionHandler를 등록한 Controller에만 적용된다. 다른 Controller에서 NullPointerException이 발생하더라도 예외를 처리할 수 없다. -> controllerAdvice 와 같이 사용하면 됨.
  • 메서드의 파라미터로 Exception을 받아왔는데 이것 또한 자유롭게 받아와도 된다.

 

 

@ControllerAdvice

@ExceptionHandler가 하나의 클래스에 대한 것이라면, @ControllerAdvice는 모든 @Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.

 

@RestControllerAdvice
public class MyAdvice {
    @ExceptionHandler(CustomException.class)
    public String custom() {
        return "hello custom";
    }
}

 

종합적으로 @ExceptionHandler 와 @ControllerAdvice 같이 사용하여야 한다.

@RestControllerAdvice
@RequiredArgsConstructor
public class CommonExceptionAdvice {

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> runtimeException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse(CustomExceptionCode.ERROR_500);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(errorResponse);
    }

    @ExceptionHandler(CustomException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> customException(Exception e) {
        ErrorResponse errorResponse = new ErrorResponse(CustomExceptionCode.ERROR_500);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(errorResponse);
    }
 }

위와 같이 특정 Exception 에 대해 응답 코드를 달리해서 처리하면 좋다.

ControllerAdvice 와 같이 사용하면 sevice 레벨에서 예외가 발생해도 handler 에 동작한다.

반응형
반응형

특정 Exception이 발생했을 경우 일정 횟수만큼 재시도할 수 있는 어노테이션이다.

 

예를 들어, 서비스 내에서 다른 서비스에 있는 API를 호출할 때 간헐적으로 통신 오류가 발생할 수 있다.

이럴 때 특정메소드에 재시도 할 수 있는 기능이 있다.

 

사용법은 아주 간단하다.

1. Spring Application에 @EnableRetry 어노테이션 추가

2. 재시도 하고 싶은 메소드에 @Retryable 어노테이션 추가

- include : 여기에 설정된 특정 Exception이 발생했을 경우 retry한다.

- exclude : 설정된 Exception 재시도 제외

- maxAttempts : 최대 재시도 횟수 (기본 3회)

- backoff : 재시도 pause 시간

 

@Retryable(maxAttempts = 2, backoff = @Backoff(2000), value = IllegalStateException.class,
            exclude = { NullPointerException.class, NullPointerException.class })
    public String retryExample(Integer intValue) {
        ~~~~~~~
        return String.format("성공");
    }
반응형

+ Recent posts

Buy Me A Coffee
방문해주셔서 감사합니다. 후원이 큰힘이 됩니다.