2021 08 26 Spring
2021-08-26 Spring¶
로깅¶
- 로깅이 왜 필요하죠? Sout에 비해 갖는 장점은? - 실시간으로 디버깅할 수 없는 상황에는 로그를 남겨 에러상황 발생시 추적할 수 있도록 해야함 - 내가 느낀바로는 - logging은 좀더 쉽게 양식을 커스텀 할 수 있다 - logging 라이브러리를 활용하여 특정한 레벨 이상의 로그 발생시 어펜더(?)를 사용하여 슬랙 알림 보낼 수 있다 - 실시간 디버깅 갬성 가능 - 파일로 차곡차곡 관리하는 것도 쉽게 제공한다 - 느껴본적은 없지만,, - 성능이 더 좋다고 들었습니당
- log4j, slf4j, logback 뭔지 알아? - slf4j - 로깅 인터페이스! JPA의 갬성 - 실제 로거 구현체로 연결을 해줌! - facade 패턴이라는데... - "어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체이다" - logback/log4j - slf4j의 구현체! hibernate의 갬성
- 왜 logback 사용했죠? - 참고: https://beyondj2ee.wordpress.com/2012/11/09/logback-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-reasons-to-prefer-logback-over-log4j/ - 우선 Spring Boot Starter의 기본 로깅 라이브러리라 추가 설치가 필요가 없었음 - log4j의 아키텍쳐 기반으로 재작성된 것이란다,,, - 성능도 빠르고, 메모리 점유도 적다는데... - 운영서버에서 서버 재시작없이 로깅 레벨 조절 가능 (써본적은 없음) - 파일에 로그 저장 일시적으로 장애 발생시 서버 재가동 필요 - logback은 서버 중지없이 이전 시점부터 복구를 graceful 하게 지원 (써본적 없음)
- 로깅 전략 공유해주세요
- 우선 로깅 레벨
- FATAL-ERROR-WARN-INFO-DEBUG-TRACE 레벨
- ERROR 이상이 의도하지 않은 익셉션
- 의도하지 않은 익셉션이다 보니 커스텀 익셉션 발생하면 INFO로 로깅 지정
- XML으로 로깅 설정 작성 후 yml에서 spring profile로 추가하여 사용
- 로깅 설정을 모듈화 할 수 있다는 것이 장점이었음
logback-spring.xml <springProfile name="console-logging"> //log 형태 설정, 로그 메시지 출력 대상 결정 요소 <appender name="LOCAL_CONSOLE_POLICY" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} %highlight([%-5level]) [%thread] %cyan([%logger{36}]) - %m%n</Pattern> </layout> </appender> </springProfile>
- 로깅 설정 읽는 순서 아시나요? - 참고: https://newwisdom.tistory.com/80?category=956402 - logback-spring.xml 있으면 설정파일 읽기 - 없다면 yml 파일의 설정 읽기 - 둘 다 있다면 yml 설정파일 적용후 xml 파일 적용
빈 생명주기¶
- 이게 뭔지 설명 좀 해주세요
- 스프링의 컨테이너 (Application Context)는 빈의 생성/소멸/주입/제공 등을 담당합니다.
- 그 과정속에서 빈이 생성 -> 주입 -> 소멸되는 과정이 있어 공부하였습니다.
- 과정은 다음과 같습니다.
1. 빈 인스턴스화 및 DI
- 어노테이션으로 빈 정의 스캔
- 빈 인스턴스 생성
- 빈 프로퍼티에 의존성 주입
2. 빈이 특정 인터페이스를 구현했다면 호출하게 됨
-
BeanNameAware-BeanClassLoaderAware-ApplicationContextAware3. 빈 생성 생명주기 콜백 -@PostConstruct4. 빈 소멸 생성주기 콜백 -@PreDestroy
- 콜백? - 어떤 이벤트가 발생했거나 특정 시점에 도달 시, 시스템에서 호출하는 함수
- 어쩌다 공부함??
- 전략패턴을 도입할 일이 있었다.
- 전략을 Enum으로 관리해서 특정조건에 맞게 Bean을 반환해주고 싶은 코드가 있었다.
- 근데 Enum이 Static 이다 보니까 Bean을 주입해주는게 힘들더라.
- Enum의 필드로 Bean을 들고 있게 하고 싶은데 Static은 클래스 로더의 로딩 작업에서 먼저 메모리에 올라가게 된다
- 빈들보다 말이지
- 그래서 Enum의 필드로 Bean을 들고 있게 하려면 나중에 Bean을 주입하는 방식의 코드 작성이 필요했다.
- 따라서 Enum에 내부 클래스를 하나 만들고 이를 Bean으로 등록해줬고,
- 해당 내부 클래스에서
@PostConstruct어노테이션을 활용하여 Enum 객체에 알맞은 Bean을 집어 넣어주었다.@Component @AllArgsConstructor private static class StrategyInjector { private NoneStrategy noneStrategy; private QueryOnlyStrategy queryOnlyStrategy; private TechsOnlyStrategy techsOnlyStrategy; private QueryAndTechsStrategy queryAndTechsStrategy; @PostConstruct private void inject() { NONE.setSearchStrategy(noneStrategy); QUERY_ONLY.setSearchStrategy(queryOnlyStrategy); TECHS_ONLY.setSearchStrategy(techsOnlyStrategy); QUERY_AND_TECHS.setSearchStrategy(queryAndTechsStrategy); } }
Spring EventListener & TransactionEventListener¶
- 왜 썼죠? - 해당 기능은 알림 기능을 구현할 때 사용했음 - 다른 사용자가 내 글에 좋아요/댓글을 달았을 때 알림을 저장해주고자 사용했다.
- 그냥 의존성 주입에 비해 갖는 장점?
- 의존성 주입에 비해 약한 의존관계를 갖게된다는 점이 있다고 공부하여 사용했었음
- 알림 기능이 딱 그랬다고 생각.
- 솔직히 어떤 사용자가 특정 글에 좋아요/댓글을 남기는 기능과 해당 글의 주인에게 알림을 남겨주는 기능은 완전히 별개의 기능
- 좋아요/댓글 남기는 로직 도중에 noficationService 같은걸 주입받아 메서드 호출해 줄 수도 있지만 너무 강한 결합이라고 판단.
- 또한 이벤트 리스너는 비동기로 처리하는 것과 굉장히 잘 어울린다고 생각
-
@EnableAsync를 통해서 해당 알림을 남기는 기능은 메인 쓰레드에서 따로 벗어나 다른 쓰레드에서 처리할 수 있도록 코드 작성했었음 - 팀원들과 얘기하면서 이게 테스트하기 힘든 코드라는 판별에 우선 없애긴했는데, 꼭 다시 데려올 예정 - 이벤트 리스너의 강점을 가장 부각할 수 있는 갬성인 것 같음
- Block vs Non-Block vs Async vs Sync? - 참고: https://brunch.co.kr/@springboot/267 - 메서드를 제공하는 곳 입장 - Sync: 메서드의 결과가 완성될 때 까지 반환하지 않는다. 기다려! - Async: 결과값이 결정되기 전에 우선 반환 - 결과 받아보는 클라이언트 입장 - Blocking: 결과 나왔나,,, 조회 (polling) - Non-Blocking: 콜백으로다가 클라이언트에게 알려줌 (webhook)
- 콜백이 뭐야? - 어떠한 함수가 비동기적으로 실행되었음 - 즉각적으로 결과값을 받아볼수가 없는 상태 - 다른 쓰레드에서 잘 끝난다음에야 콜백으로 호출된거 처리할 거 있으면 처리해줌