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으로 하나씩만 생성하자!
- 외부 파일의 값을 이용하기
-
@Properties- 참고: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-using-propertysource - Spring Environment에 PropertySource를 손쉽게 추가하도록 함 - key-value의 쌍들로 이루어진 .properties 파일들을 추가해준다면, env.getProperty("key"); 를 통해 가져오기 가능-
@Value- 참고: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-value-annotations - 참고: https://www.baeldung.com/spring-value-annotation - Properties를 읽는 방법 중 하나 - 외부 property들의 값을 주입할 때 사용 - Spring이 관리하는 bean들에 값들을 주입할 수 있는 어노테이션 - Configuration 클래스에서@PropertySource설정을 해두자 -@Value("${systemValue}")를 통해 주입가능 - 환경에 따라 Bean/Property 값을 다르게 할 수 있음 -@Profile- 참고: http://wonwoo.ml/index.php/post/1933 - 각 환경 (profile) 에 맞게 Spring의 Bean들을 올릴 수 있음 - dev / test / prod
- 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 예외 처리 전략¶
- 참고 1: https://cheese10yun.github.io/spring-guide-exception/
- 참고 2: https://devkingdom.tistory.com/118
- 참고 3: https://www.baeldung.com/exception-handling-for-rest-with-spring
- 통일된 Error Response 객체 생성
- 리턴 타입이 ResponseEntity
로 무슨 데이터가 어떻게 있는지 추론할 수 있게 하자
- Error Response JSON - 에러에 대한 정보를 반환하는 JSON은 다음과 같이 작성해보자
@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: 산수를 잘못한 경우