콘텐츠로 이동

2021 05 26

2021-05-26

브라운 Spring config 수업 복습

  • 배경 지식 강의 - [컨테이너 설정 방법] - XML
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userRepository" class="nextstep.helloworld.core.xmlConfig.UserRepository"/>
    
        <bean id="userService" class="nextstep.helloworld.core.xmlConfig.UserService">
            <property name="userRepository" ref="userRepository"/>
        </bean>
    </beans>
    
      - Annotation-based configuration
          - `@AutoWired`
      - Java-based Configuration
          ```java
          @Configuration
          public class AppConfig {
              @Bean
              public MyService myService() {
                  return new MyService();
              }
          }
          ```
    
  • Java-based Configuration
    @Configuration
    public class AuthenticationPrincipalConfig {
    
        @Bean
        public AuthService authService() {
            return new AuthService();
        }
    
        @Bean
        public AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver() {
            return new AuthenticationPrincipalArgumentResolver(authService());
        }
    }
    

    - 생성하는 authService()와 주입 받는 authService()는 동일하다! - 빈 등록시 의존이 필요하면 먼저 생성하고 의존한다 - Singleton으로 하나씩만 생성하자!

  • Configuration의 역사 - XML -> Java-based config - Spring Boot & Auto Configuration - Spring Boot - 바로 실행할 수 있는 어플리케이션을 쉽게 만들 수 있게 도와줌 - Auto-config - 별다른 설정을 안해주었음에도 DB, JdbcTemplate 등등 다 잘씀 - @EnableAutoConfiguration - jar dependency 기반으로 스프링 어플리케이션 자동 설정 - 'org.springframework.boot.starter~~~' - 엄청 많은 auto configuration이 자동으로 로딩됨 - 예시) JdbcTemplateAutoConfiguration - Dao에서 JdbcTemplate 안만들고 알아서 주입되서 잘 사용됨 - spring.factories 내의 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration 에서 설정을 해둠 - @Condition, @Conditional - 조건에 따라 설정할 수 있도록 auto-config
  • 과제 - Auto Configuration 디버깅 해보자! - Spring Boot Application 디버깅 해보자!

Spring 예외 처리 전략

  • Error Response JSON - 에러에 대한 정보를 반환하는 JSON은 다음과 같이 작성해보자
    {
      "message": "해당 이메일로 등록된 사용자가 이미 있습니다.",
      "errors": [
        {
          "field": "member.email",
          "value": "test@test.com",
          "reason": "Duplicated Email"
        }   
      ] 
    }
    
  • @ControllerAdvice를 통한 모든 예외 핸들링 - @ControllerAdvice를 통해 모든 예외를 한 곳에서 처리 가능 (전역 발생 예외 딱 대) - 여러곳으로 산재되어 있던 @ExceptionHandler들을 하나의 전역 컴포넌트로 모아줌 - @ExceptionHandler를 통해 잡아줄 예외를 작성해두자! - @Controller, @RestController가 적용된 Bean 내에서 발생하는 예외를 잡아 하나의 메서드에서 처리해주는 기능 제공 - Controller-Level에서의 처리 - 컨트롤러에서만 쓰인다면 이게 또 단점인게 해당 Controller에서만 에러를 잡을 수 있음 - 가장 기본적이며, 필수적으로 처리할 예외의 모음 - 주어진 예시 - (MethodArgumentNotValidException.class) - Spring Validation으로 처리한 @Valid에서 주로 발생 - @RequestBody, @RequestPart에서 발생 - (MethodArgumentTypeMismatchException.class) - 알맞은 enum 타입으로 binding 못할 경우 발생 - (HttpRequestMethodNotSupportedException.class) - 지원하지 않는 HTTP 메서드 호출시 발생 - (AccessDeniedException.class) - Authentication 객체가 필요한 권한 가지지 않은 경우 발생 - (BusinessException.class) - 비즈니스 요구 사항에 따른 Exception - 개발자가 직접 Exception을 발생시키는 것들 - (Exception.class) - 그 밖에 발생하는 모든 예외 처리 (NPE 등) - 개발자가 핸들링하지 않은 것 모두 모임
  • ErrorCode는 Enum으로 한번에 관리해보자
    - 상태코드, 메시지, 필요시 식별코드도 모두 포함
  • Controller에서 Validation 책임을 하도록 하자 - @Valid, @NotNull 등의 Spring Bean Validation을 통해 뚝딱 검증 - 클래스 필드에 특정 annotation을 붙여 필드의 제약 조건 정의
  • Try-Catch 전략 - 만일 try-catch를 사용한다면 구체적인 예외로 Exception을 발생시키자! - 클린코드: "try/catch 블록은 원래 추하다. 코드 구조에 혼란 일으키며, 정상 동작과 오류 처리 동작을 뒤섞는다."
  • 전역에서 모든 예외를 잡아주기
    @ControllerAdvice
    @RestController
    public class GlobalExceptionHandler {
    
        @ExceptionHandler(value = Exception.class)
        public ResponseEntity<ErrorMessage> handleException(Exception e) {
            ErrorMessage errorMessage = ErrorMessage.of(e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(errorMessage);
        }
    }
    
  • HandlerExceptionResolver - @ResponseStatus를 사용하여 Custom Exception에 대해 HTTP 상태 코드를 지정
  • ResponseStatusException
    - 커스텀 예외 조금씩 줄이기 가능 - 프로그래밍 적으로 예외처리 가능 - 근데 이게 통일된 방법이 없어 - 코드 중복 많이 발생
    @GetMapping(value = "/{id}")
    public Foo findById(@PathVariable("id") Long id, HttpServletResponse response) {
        try {
            Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
    
            eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
            return resourceById;
         }
        catch (MyResourceNotFoundException exc) {
             throw new ResponseStatusException(
               HttpStatus.NOT_FOUND, "Foo Not Found", exc);
        }
    }
    

Java Exception 종류

  • 참고 1: https://stackify.com/types-of-exceptions-java/
  • Checked Exception - SQLException: DB를 향한 쿼리가 파토난 경우 - IOException: File I/O가 파토난 경우 - ClassNotFoundException: JVM이 찾으려는 클래스 못찾은 경우
  • UncheckedException
    - NullPointerException: 참조하려는 객체가 null인 경우 - ArrayIndexOutofBound: 배열 범위 넘어간 경우 - IllegalArgumentException: 메서드에 부적절한/맞지 않는 파라미터가 넘어간 경우 - IllegalStateException: 현재 객체의 상태가 운영적으로 로직에 맞지 않는 경우 - NumberFormatException: 다른 타입으로 변환하려는데 실패한 경우 - ArithmeticException: 산수를 잘못한 경우