월 16,940원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결스프링 핵심 원리 - 고급편
전략패턴 질문이요!
안녕하세요 영한님 백엔드 3년차 개발자인데 정말 잘듣고있습니다! 전략 패턴 강의 듣고 궁금증이 생겨서요~ 전략 패턴도 인터페이스안에서 메소드 선언이 추가되거나 하면 해당 인터페이스를 구현하고있는 구현 클래스들도 각각 일일이 찾아가서 강제로 구현해야되는 점이 있는것 같은데 이런것은 실무에서 상관없을까요??
- 미해결스프링 핵심 원리 - 고급편
빈후처리기와 @postconstruct
안녕하세요 빈 생성후에 @postconstruct나 intializing의 afterpropertyset 을 이용해서 후처리를 할 수 있는데 빈후처리기의 차임점은 기본 빈의 가공을 넘어서 객체 변환까지 가능하다고 알고 있으면 될까요?? 항상 좋은 강의 감사드립니다.!
- 미해결스프링 핵심 원리 - 고급편
PointCut 표현식을 컴파일 타임에 에러체크 할 수 있을까요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Pointcut Expression 작성 시에 오타가 자주 발생하여 런타임 에러를 자주 만납니다. 쿼리를 자바 컴파일 타임에 검사 할 수 있게 해주는 QueryDSL 처럼 PointCut Expression 도 컴파일 타임에 에러를 발생시켜주는 방법이 있을까요?
- 미해결스프링 핵심 원리 - 고급편
포인트컷 within에 의한 this, target의 필요성
this와 target의 차이는 이해했습니다. 그런데, 이것들이 과연 필요가 있는지에 대해서 의문이 들었습니다.저라면 this 대신 target 쓸 것 같고 target 대신 within을 쓸 것 같습니다. 그러나, 아무 필요성 없이 두 포인트컷이 생기지는 않았을 것 같습니다.within대신 target, target 대신 this를 사용하는 구체적인 경우가 언제인가요? 두 포인트컷은 왜 존재하나요?
- 미해결스프링 핵심 원리 - 고급편
ConcurrentHashMap 사용 질문
https://www.inflearn.com/questions/347336 해당 질문 글에서 ConcurrentHashMap 을 사용하더라도 예제에 발생하는 동시성 이슈를 막을 수 없다고 하셔서 저도 궁금해서 ConcurrentHashMap 을 사용한 LogTrace를 만들어서 테스트를 몇 번 돌려봤는데 정상적으로 처리되는거 같은데 또 다른 이슈가 있는건가요?? package hello.advanced.trace.logtrace; import java.util.concurrent.ConcurrentHashMap; import hello.advanced.trace.TraceId; import hello.advanced.trace.TraceStatus; import lombok.extern.slf4j.Slf4j; @Slf4j public class MapLogTrace implements LogTrace { private static final String START_PREFIX = "-->"; private static final String COMPLETE_PREFIX = "<--"; private static final String EX_PREFIX = "<X-"; private ConcurrentHashMap<Thread, TraceId> map = new ConcurrentHashMap<>(); @Override public TraceStatus begin(String message) { syncTraceId(); Long startTimeMs = getCurrentTimeMillis(); TraceId traceId = map.get(Thread.currentThread()); log.info("[{}] {}{}", traceId.getId(), addSpace(START_PREFIX, traceId.getLevel()), message); return new TraceStatus(traceId, startTimeMs, message); } private void syncTraceId() { Thread thread = Thread.currentThread(); TraceId traceId = map.get(thread); if (traceId == null) { map.put(thread, new TraceId()); } else { map.put(thread, traceId.createNextId()); } } @Override public void end(TraceStatus status) { complete(status, null); } @Override public void exception(TraceStatus status, Exception ex) { complete(status, ex); } private void complete(TraceStatus status, Exception ex) { Long stopTimeMs = getCurrentTimeMillis(); long resultTimeMs = stopTimeMs - status.getStartTimeMs(); TraceId traceId = status.getTraceId(); if (ex == null) { log.info("[{}] {}{} time={}ms", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs); } else { log.info("[{}] {}{} time={}ms ex={}", traceId.getId(), addSpace(EX_PREFIX, traceId.getLevel()), status.getMessage(), resultTimeMs, ex.toString()); } releaseTraceId(); } private void releaseTraceId() { Thread thread = Thread.currentThread(); TraceId traceId = map.get(thread); if (traceId.isFirstLevel()) { map.remove(thread); } else { map.put(thread, traceId.createPreviousId()); } } private String addSpace(String prefix, int level) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < level; i++) { sb.append((i == level - 1) ? "|" + prefix : "| "); } return sb.toString(); } private Long getCurrentTimeMillis() { return System.currentTimeMillis(); } }
- 미해결스프링 핵심 원리 - 고급편
AspectJ의 AOP 구현방식에 대해 질문드립니다.
1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용] 영한님 안녕하세요! Spring AOP는 프록시 기반으로 타겟과 aspect를 weaving해서 프록시 객체가 생성된다고 이해했습니다. 그렇다면 또다른 AOP 프레임워크인 aspectJ는 어떤 방식으로 aspect를 타겟에 적용하고 있나요? AspectJ가 적용된 코드에 final을 붙여 실행시켰을 때 오류가 나는 것으로 보아 아마 프록시로 래핑된 객체를 생성하지 않을까 추측이 되는데 확실치 않아 여쭤봅니다. 짜임새 있는 강의 준비해주셔서 항상 잘 듣고 있습니다. 고맙습니다!
- 미해결스프링 핵심 원리 - 고급편
오타 수정 문의
안녕하세요~~ 영한님! '포인트컷 지시자의 종류 종류' 종류가 2번 들어가있습니다!!
- 미해결스프링 핵심 원리 - 고급편
두 가지 문의 드립니다
안녕하세요. 두 가지 문의 드립니다. 1. execution에서 type이 있는 varargs param 조건을 정의할 수 있을까요? 예를 들면 foo(String... params) 의 조건만을 만족시키는 것 입니다. 2. 그리고 param 조건에도, super type을 지정할 경우 공변성이 있는 하위 타입(Generic, collection 포함)들은 모두 대상이 되는걸까요? 감사합니다!
- 미해결스프링 핵심 원리 - 고급편
@order 문의 드립니다
안녕하세요. @Order가 적용 된 Aspect끼리는 순서가 보장되는 것을 이해 했는데요. @Order가 적용 된 Aspect와 적용되지 않은 Aspect를 섞어서 사용할 때는 순서가 어떻게 적용 되는 지 문의 드립니다. 예) @Order가 붙은 순서대로 먼저 적용 된 후, 안 붙은 Aspect들의 실행 순서는 보장되지 않는다.
- 미해결스프링 핵심 원리 - 고급편
aop 적용 범위 문의
안녕하세요. point cut 적용 범위가 hello.aop.order의 모든 하위 패키지로 지정되었는데요. 조건만 봐서는 AspectV1의 doLog() 또한 AOP 적용 대상이 될 것 같습니다. (AspectV1도 bean으로 등록 되었으므로..) 물론 그렇게 되면 끊임 없이 doLog가 호출될 것이므로, 제외 할 것 같은데요. 어떤 조건을 보고 AOP 적용 대상에서 제외를 하는 걸까요? (@Aspect, @Around 등...)
- 미해결스프링 핵심 원리 - 고급편
OrderRepositoryV3 sleep 함수 관련 질문
[질문 내용]OrderRepository class 에서 Thread.sleep()을 바로 save() 로직안에서 사용 안하고 따로 private 함수로 빼서 sleep()을 다시 만든 이유가 있을까요?? public void save(String itemId) { AbstractTemplate<Void> template = new AbstractTemplate<>(trace) { @Override protected Void call() { if (itemId.equals("ex")) { throw new IllegalStateException("예외 발생!"); } sleep(1000); return null; } }; template.execute("OrderRepository.save()"); } private void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } }
- 미해결스프링 핵심 원리 - 고급편
리턴 타입이 void 인 메서드를 테스트 하는 방법이 있나요?
안녕하세요 해당 강의 마지막 부분에서 테스트 코드를 작성하신 부분에서 궁금증이 생겼습니다. 강의에서는 콘솔에 출력하는 방식으로 대략적인 테스트를 진행하셨습니다. (이게 진짜 테스트가 아니라는 점도 이해했습니다) 제 스스로 검증 코드를 만들어 테스트해보고 싶어 시도했는데, trace.end() 나 trace.exception() 의 리턴 타입이 void 라 어떻게 assertThat() 의 인자로 넣어야 할지 모르겠더라구요,, 혹시 이렇게 리턴타입이 없는 메소드를 테스트할 수 있는 방법은 무엇이 있을까요? 좋은 강의 늘 감사합니다. :))
- 미해결스프링 핵심 원리 - 고급편
강의교재 내용 질문드립니다.
4. 프록시 패턴과 데코레이터 패턴 pdf p.7에 보면 아래와 같은 내용이 나옵니다. @Configuration 은 내부에 @Component 애노테이션을 포함하고 있어서 컴포넌트 스캔의 대상이 된다. 따라서 컴포넌트 스캔에 의해 hello.proxy.config 위치의 설정 파일들이 스프링 빈으로 자동 등록 되지 않도록 컴포넌스 스캔의 시작 위치를 scanBasePackages=hello.proxy.app 로 설정해야 한다. 위의 내용이 AppV1Config.java를 @Configuration을 붙였는데 @Configuration 안에는 Component가 있어서 자동으로 스프링 빈 등록이 되므로 이걸 막기 위해 scanBasePackages=hello.proxy.app 설정을 해준다. 즉 AppV1Config를 빈 등록을 막기위해 한다는 뜻인가요?
- 미해결스프링 핵심 원리 - 고급편
logTrace의 Level이 높게 출력되는 문제를 겪고있어 질문올립니다
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용 & 문제점] - 안녕하세요 강의 진행도중, "쓰레드로컬 동기화" 부분을 진행하다 조금 의하하게 동작하는 부분이 있어서 질문올립니다! - 제가 이해한 강의 흐름은 1) 필드변수를 사용해서 동기화한다 >> 동시성 문제 발생 2) 쓰레드 로컬을 사용해서 동시성 문제를 해결한다! - 위 순서인데, 쓰레드 로컬을 사용한 코드에서도 log의 depth 가 올바르게 정상적인 깊이로 표시되지 않고 여러번 반복되서 붙는 문제가 있습니다 - 문제증상이 발생할때의 로그는 아래처럼 찍힙니다 ``` 2022-01-01 11:54:07.809 INFO 2553 --- [nio-8080-exec-9] h.a.trace.logtrace.ThreadLocalLogTrace : [4202b619] | | | | | | | | | | | | | | | | | | | | |-->,OrderControllerV3-request()! 2022-01-01 11:54:07.809 INFO 2553 --- [nio-8080-exec-9] h.a.trace.logtrace.ThreadLocalLogTrace : [4202b619] | | | | | | | | | | | | | | | | | | | | | |-->,OrderServiceV3.orderItem() 2022-01-01 11:54:07.809 INFO 2553 --- [nio-8080-exec-9] h.a.trace.logtrace.ThreadLocalLogTrace : [4202b619] | | | | | | | | | | | | | | | | | | | | | | |-->,v3 Repository.save() 2022-01-01 11:54:07.810 INFO 2553 --- [nio-8080-exec-9] h.a.trace.logtrace.ThreadLocalLogTrace : OK:[4202b619] | | | | | | | | | | | | | | | | | | | | | |<--,OrderServiceV3.orderItem() time=1ms OK!! 2022-01-01 11:54:07.810 INFO 2553 --- [nio-8080-exec-9] h.a.trace.logtrace.ThreadLocalLogTrace : OK:[4202b619] | | | | | | | | | | | | | | | | | | | | |<--,OrderControllerV3-request()! time=1ms OK!! ``` - 제가 겪고 있는 문제를 시연하는 영상입니다 [https://youtu.be/hBYAinNtMxg] [시도한 방법] - 첫번째로 수업을 따라가며 작성한 코드가 있는지 검증했는데요, IDE 코드 비교 기능을 이용해서 교안과 제가 작성한 코드 사이의 다른 부분으로 인한 버그인지 순차적으로 탐색해봤는데 발견하지 못했습니다 - 두번째로 Debug 모드로 실행해봤는데, 실제로 addSpace() 함수에 level 에 값이 10, 11, 12~~ 로 점점 증가하게 들어왔습니다. 대략 브라우저에서 새로고침을 통해 Request를 10번 보낼때마다 level 값이 1스텍씩 증가합니다 [질문] Q1) 진행하시는 강의에서처럼 1초에 두번 세번정도까지 요청을 날리면 정상적으로 동작 하는데, 그 이상으로 브라우저에서 refresh 연타를 날리면 발생하는 문제인데, 혹시 해당동작은 "정상동작" 범주에 벗어나는 비정상적인 요청인가요?? Q2) 디버깅을 하는 중인데, Depth Level이 높게 들어오는 부분이 InteliJ에서도 확인 가능한데요, 이걸 근거로 요청을 보내는 브라우저의 문제가 아닌 코드상의 문제로 생각이 드는데 올바른 해결 방향일지 궁금합니다 [실행환경 & 재현하는 방법] - 코드 : https://github.com/d-h-k/Spring_PlayGround/tree/v0.220101/spring-advenced/advenced - 위 링크에서 tag v0.220101 로 만들어놓았고, /spring-advenced/advenced 디렉토리 하위의 인텔리제이 프로젝트로 실험을 진행했습니다 - (위 링크와 동일)증상은 여기 링크의 영상에서 확인 가능합니다 : https://youtu.be/hBYAinNtMxg
- 미해결스프링 핵심 원리 - 고급편
this 질문드립니다.
안녕하세요. 강의를 듣다가 궁금증이 생겨 질문드립니다. 이전 강의에서 프록시가 생성되는 과정을 보면 1. @Aspect 애노테이션을 클래스에 선언하고 클래스 안에 @Around로 포인트컷 표현식을 정의하고, @Around가 붙은 메서드로 이제 어드바이스를 정의 2. 스프링 애플리케이션이 초기화 될 때 자동프록시생성기가 @Aspect가 붙은 클래스를 다 찾아서 어드바이저생성 3. 이제 스프링 빈으로 등록될 객체들을 하나씩 불러와서 어드바이저의 포인트컷을 통해 프록시 대상인지 아닌지 확인해서 프록시를 생성하여 스프링 빈으로 등록 으로 이해를 하였는데요. 이번 강의에서 @Aspect 클래스 안에 메서드에 @Around("this(hello.aop.member.MemberService)") 이런식으로 this에 타입을 정의하는데, 초기화 시점에 스프링 빈 대상 객체들을 this 포인트컷 표현식으로 프록시 대상 객체인지 아닌지 확인할 수가 없지 않나요? 왜냐하면 아직 프록시가 생성되기 전인데 어떻게 this(프록시 객체)을 판단할수가 있는건가요? 아니면 모든 빈을 일단 프록시로 만들고 실행시점에 판단하는 방식인가요? 감사합니다.
- 미해결스프링 핵심 원리 - 고급편
JpaRepository 로그 출력이 안됩니다
안녕하세요 강의를 우선 한번 다 듣고 예제를 직접 만들어보면 학습을 하고있는데 다음과같은 문제가 생겼습니다 간단한 controller - service - repository 구조의 api를 만들었는데 controller - service 까지는 로그가 잘 찍히는데 레포지토리에서 로그가 찍히지 않았습니다(소스가 코틀린이 죄송합니다..) @Aspect@Componentclass LogTraceAspect(private val logTrace: LogTrace) {// @Around("execution(* com.example.logger.app..*(..)) || target(com.example.logger.app.repository.MemberRepository)")// @Around("execution(* com.example.logger.app..*.*(..))") @Around("within(com.example.logger.app..*)") @Throws(Throwable::class) fun execute(joinPoint: ProceedingJoinPoint): Any { var status: TraceStatus? = null return try { val message = joinPoint.signature.toShortString() status = logTrace.begin(message) val result = joinPoint.proceed() logTrace.end(status) result } catch (e: Exception) { logTrace.exception(status!!, e) throw e } }} package com.example.logger.app.repositoryimport com.example.logger.app.entity.Memberimport com.example.logger.app.entity.Teamimport com.example.logger.app.redis.TeamDtoPointimport org.springframework.data.jpa.repository.JpaRepositoryimport org.springframework.data.repository.CrudRepositoryinterface TeamRepository : JpaRepository<Team, Long>interface MemberRepository : JpaRepository<Member, Long>interface TeamRedisRepository : CrudRepository<TeamDtoPoint, String> 첫번째로 주석처리된 포인트컷처럼 target으로 직접 repository를 지정해주면 로그가 찍히는데 그렇지 않을 경우에는 로그가 찍히지 않았습니다. (TeamRepository, MemberRepository 둘다) 그런데 이상한건 같은 패키지에 있는 redis용 레포지토리인 TeamRedisRepository는 로그가 찍힙니다.. 제가 어떤 부분을 놓치고 있는 걸까요?? 전체 소스코드는 https://github.com/rkdals213/logger 여기있습니다
- 미해결스프링 핵심 원리 - 고급편
Pointcuts 클래스를 빈으로 등록 안한 이유
Pointcust 클래스를 빈으로 등록하니깐 @Around("Pointcuts.allOrder()") 이렇게 해도 되는데 왜 강의에서는 경로를 지정해서 한건가요? 둘이 어떤 차이점이 있는건가요?
- 미해결스프링 핵심 원리 - 고급편
오타 확인 부탁드립니다.
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용] 수업 자료 중 3.템플릿 메서드 패턴과 콜백 패턴.pdf의 39번 page의 OrderServiceV5의 public void orderItem(String itemId) 메서드 내부의 template.execute()의 파라미터로 들어가는 문자열이 OrderController.request() -> OrderService.orderItem() 로 바뀌어야할 것 같습니다. 감사합니다.
- 미해결스프링 핵심 원리 - 고급편
was가 여러대일 경우
강의 감사드립니다. (__) was가 2대 이상인 경우에도 Thread local이 동시성 이슈를 막을 수 있는지가 궁금합니다.
- 미해결스프링 핵심 원리 - 고급편
오타가 있는 것 같습니다.
안녕하세요! 8분 24초에서 '프록시 부분 보세요. 얘가 MemberService를 알수 있을까요 없을까요. 얘는 MemberService를 전혀 알수 없어요' 이렇게 말씀하시는데 MemberService가 아니라 MemberServiceImpl 아닌가 싶어서 글 남깁니다. 뒤에서 설명하실때도 MemberServiceImpl이라고 하셔서요! 항상 좋은 강의 감사합니다 :) Spring Batch, Spring Security도 기회가 된다면 커리큘럼에 넣어주세요 !!