묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 핵심 원리 - 고급편
추상클래스 autowired 및 빈 등록 관하여 질문이 있습니다.
강의해주신 소스코드에서, 추상클래스에 @Component와 멤버변수에 @Autowired를 붙이지 않는 모습을 보여주셨습니다. 이와 관련해서 여러 실험을 해보다보니 궁금한 점이 생겼습니다. 궁금한 점은,추상 클래스에 @Component를 붙여도 왜 정상작동하는 지 모르겠습니다. -> 추상 클래스는 객체 생성이 불가능한 것으로 알고 있는데, 어떻게 빈에 등록되는 건가요?(제네릭이라 빈컨테이너에서 가져오는 것도 쉽지 않네요..)위의 코드에서 @Autowired를 붙이고, 생성자를 지웠습니다.이미 빈에 등록된 LogTrace를 꺼내서 사용하고자 하는데 왜 null이 반환되어 널포인터예외가 발생합니다. 이는 왜 불가능한 것인가요??
-
해결됨스프링 핵심 원리 - 고급편
인터페이스 기반 프록시 적용 후 orderController bean method 오류
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]인터페이스 프록시를 적용한 뒤 프로젝트를 실행 하니 아래와 같은 오류가 발생했습니다.org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'orderControllerImpl' method hello.proxy.app.config.v1_proxy.interface_proxy.OrderControllerInterfaceProxy#request(String) to {GET [/v1/request]}: There is already 'orderControllerV1' bean method hello.proxy.app.v1.OrderControllerV1Impl#request(String) mapped.검색해보니 매핑 정보가 겹쳐있다고 나오는데제가 보기에는 어디가 겹친 건지 모르겠더라구요..강의 코드도 비교 해봤는데 비슷한거 같고..어디가 문제인지 궁금합니다.해당 오류가 발생한 OrderControllerInterfaceProxy와 OrderControllerV1Impl 코드 첨부합니다.ProxyApplication@Import(InterfaceProxyConfig.class) @SpringBootApplication(scanBasePackages = "hello.proxy.app") // app 패키지 하위만 컴포넌트 스캔의 대상이 된다. public class ProxyApplication { public static void main(String[] args) { SpringApplication.run(ProxyApplication.class, args); } @Bean public LogTrace logTrace() { return new ThreadLocalLogTrace(); } }OrderControllerInterfaceProxy@RequiredArgsConstructor public class OrderControllerInterfaceProxy implements OrderControllerV1 { private final OrderControllerV1 target; private final LogTrace logTrace; @Override public String request(String itemId) { TraceStatus status = null; try { status = logTrace.begin("OrderController.request()"); // target 호출 String result = target.request(itemId); logTrace.end(status); return result; } catch (Exception e) { logTrace.exception(status, e); throw e; } } @Override public String noLog() { return target.noLog(); } } OrderControllerV1Impl@Slf4j public class OrderControllerV1Impl implements OrderControllerV1 { private final OrderServiceV1 orderService; public OrderControllerV1Impl(OrderServiceV1 orderService) { this.orderService = orderService; } @Override public String request(String itemId) { orderService.orderItem(itemId); return "OK"; } @Override public String noLog() { return "OK"; } } OrderControllerV1 (인터페이스)@RequestMapping("/v1") // 스프링은 @Controller 또는 @RequestMapping 이 있어야 스프링 컨트롤러로 인식한다. (수동 등록 사용으로 @Controller 사용 안함) @ResponseBody public interface OrderControllerV1 { @GetMapping("/request") String request(@RequestParam("itemId") String itemId); @GetMapping("/no-log") String noLog(); }
-
미해결스프링 핵심 원리 - 고급편
공통 코드를 추상 클래스로 올리라는 것의 해석
첫 번째 질문은 '섹션 4'에 '데코레이터 패턴 - 예제 코드3' 편에서 김영한님이 private Component component; TimeDecorator(Component component) { this.component = component; }를 드래그하며 MessageDecorator에서와의 중복 코드이기 때문에 추상 클래스를 만들어서 올릴 수 있다고 하셨는데 추상 클래스를 아래와 같이 만들어주고@Getter @Setter public abstract class AbstractDecorator implements Component { private Component component; AbstractDecorator(Component component) { this.component = component; } } MessageDecorator를 이렇게 수정해주면 되는걸까요?@Slf4j public class MessageDecorator extends AbstractDecorator{ public MessageDecorator(Component component) { super(component); } @Override public String operation() { log.info("MessageDecorator 실행"); String result = super.getComponent().operation(); String decoResult = "**" + result + "**"; log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후={}",result, decoResult); return decoResult; } } 두 번째 질문은 추상클래스를 사용한다면 인터페이스의 장점을 활용하지 못할 것 같은데 이걸 의도하신 게 맞는지 궁금합니다. 감사합니다. 강의 잘 듣고 있습니다.
-
해결됨스프링 핵심 원리 - 고급편
LogTrace Prototype Bean으로 설정 시
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요! LocalThread 수강 중 궁금증이 생겨 질문드립니다.다음과 같이 LogTrace를 Prototype Bean으로 등록 후 컨트롤러에서 주입받아 사용하는 상황은 Thread safe 하다고 말할 수 있는지 궁금합니다package hello.advanced.app.v3; import hello.advanced.trace.TraceStatus; import hello.advanced.trace.hellotrace.HelloTraceV2; import hello.advanced.trace.logtrace.LogTrace; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor public class OrderControllerV3 { private final OrderServiceV3 orderService; private final ObjectProvider<LogTrace> provider; @GetMapping("/v3/request") public String request(String itemId) { TraceStatus status = null; LogTrace trace = provider.getObject(); try { status = trace.begin("OrderController.request()"); orderService.orderItem(trace, itemId); trace.end(status); return "ok"; } catch (Exception e) { trace.exception(status, e); throw e; } } } 만약 그렇다면, ThreadLocal을 통해 할당하고 접근하는 것과 어떤 차이가 있는지 궁금합니다.프로토타입 빈에 대한 이해가 부족한 것 같아 터무니없는 질문일 수 있지만, 잘 이해가 가지않아 질문드립니다
-
해결됨스프링 핵심 원리 - 고급편
3:26 HelloTraceV1이 import 되지 않습니다
안녕하세요, 아래처럼 HelloTraceV1이 import 되지 않아 문의드립니다.
-
해결됨스프링 핵심 원리 - 고급편
포인트컷 활용 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요.개인 토이 프로젝트에 생성과 관련된 트랜잭션이 발생할 때마다 로그를 남기는 기능을 aop를 적용 해서 만들어 보고 싶어서 새로운 어노테이션을 만들어서 구현을 했습니다. 그런데 이렇게 구현하면 aop의 장점인 본래 코드를 수정하지 않고 적용할 수 있다는 점을 놓치게 되는것 같아서 고민이 생겼습니다.새로운 어노테이션을 만들어서 적용하는 것과 관련된 메서드의 이름을 전부 통일( "ex) create~~()" ) 하는 것 중에 어떤 방법이 좀 더 좋은 방법일지 기준이 잘 안섭니다. 사진도 같이 첨부하겠습니다. 감사합니다.+) 혹시 스프링 시큐리티에 대한 강의가 계획에 있으신지 궁금합니다. 당장 계획이 없으시다면 공부하기 좋은 도서도 추천해주시면 감사하겠습니다.
-
미해결스프링 핵심 원리 - 고급편
begin_exception() 에러 로그가 출력되지 않습니다
안녕하세요, 마지막 Test 작성 중에 원하는 상황이 나오지 않아 글 올립니다.아래와 같이 begin_exception() 을 수행하는데 예외가 아니라 정상 출력이 됩니다.어떻게 해야 에러 로그가 뜨는지 알고싶습니다.
-
해결됨스프링 핵심 원리 - 고급편
로그추적기 V1적용 작은 궁금증 하나 있습니다!
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]선생님 안녕하세요 정말 별거 아닌 질문일수도있지만혹시 status를 try문이 들어가기 전에 trace.begin해주면 안되는 이유가 있을까요??강의에서는 null로 먼저 초기화를 해주셨는데 왜 이렇게 하셨는지 궁금합니다!try문으로 들어가서부터 시간을 체크하기 위함인가요??매번 좋은 강의 감사합니다!
-
미해결스프링 핵심 원리 - 고급편
데코레이터 구성 시 AOP를 사용해도 되는가
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요. 강의 잘 듣고 있습니다.질문은 "단순 데코레이터를 만들고 싶을 때 SpringAOP를 사용해도 되는가?"입니다.질문 매뉴얼의 답이 없는 질문에 포함되는 것 같아 부가설명을 적어보겠습니다. 개인적으로 이전부터 관심사와 의존성을 분리하고 싶어 데코레이터 패턴을 한번씩 쓸 때가 있었습니다.예를 들면 다음과 같습니다.게시글이 작성되면 특정 유저들에게 알림 메세지를 전송해야 한다.게시글이 수정되면 읽기 전용 모델의 캐시를 갱신해야 한다.그럼 [컨트롤러 - 알림데코레이터 - 캐시데코레이터 - 서비스 - 리포지토리 ]가 되는 거죠.이 때 데코레이터-서비스 체인을 구성해야 하는데 2가지 방법이 있었습니다.@Configuration에서 매뉴얼하게 체인 구성한 뒤 빈 생성가장 앞단의 데코레이터에 Primary를 달고 이후 순서에 따라 생성자 파라미터 주입시 @Qualifier로 구현체 주입1번 같은 경우에는 각 데코레이터마다 의존성이 많아질 수록 작성해야 하는 코드가 많아져서 제외를 했습니다.그래서 2번 방법을 사용하고 있고 다음과 같은 문제를 대면했습니다.특정 구현체가 뒷 순서 구현체를 알아야 한다. (의존성 발생) 그것도 컴파일 에러가 나지 않는 문자열(빈 이름)의 형태로.public class PostServiceMessageDecorator implements PostService { private final PostService postService; public PostServiceMessageDecorator( @Qualifier("postServiceCacheDecorator") PostService postService ) { this.postService = postService; } }체인 순서를 구성하는 것이 다소 번거롭고, 순서가 변경되거나 추가, 제거되면 코드를 바꿔야 한다. (다시 한 번 컴파일 에러가 나지 않는 문자열의 형태로)서비스 내에서 데코레이터가 붙지 않는 메소드도 구현을 해줘야 한다.그런데 SpringAOP를 사용하면 3가지 문제를 모두 해결할 수 있는 것이 아닌가 하는 생각이 듭니다.포인트컷도 잡는 것만 잡으면 되니까 데코레이터가 굳이 안붙어도 되는 메소드를 구현할 필요도 없구요.Order로 순서도 간편하게 변경이 가능하니까요.앞서 강의에서 패턴은 의도가 중요하지 실제 구현체는 다양한 방법으로 구현될 수 있다고 하신 말씀이 머릿속에 맴도는데...Aspect를 만들고 네이밍만 EntityServiceSomethingDecorator 라고 이름만 붙이면 되는게 아닌가 하는 생각이 듭니다.그러나 이 방법을 사용하는데 약간의 거부감이 있는데 AOP가 태생적으로 횡단 관심사를 해결하기 위한 기술이라는 사실 때문입니다.저는 흩어져 있는 공통 관심사 코드를 여기 저기 작성하지 않고 한 군데에서 작성하도록 한 게 개발 의도라고 생각했거든요.하지만 예시의 경우는 흩어져 있는 관심사가 아니라 특정 로직에 부가 로직을 몇 개 붙였다 뗐다 하고 싶을 뿐입니다.그렇다면 단순 데코레이터를 만들기 위해 SpringAOP를 사용하는 것은 SpringAOP의 개발 의도와는 약간 다른 사용법이 될 수 있고,보통 특정 기능을 개발 의도와 다른 방향으로 사용하면 예상하지 못한 부작용이 발생하더라구요.이 지점에서 혹시 인사이트를 얻을 수 있을지 질문을 올려봅니다.질문을 조금 다르게 얘기하면 "특정 메서드 혹은 클래스만을 위한 Aspect를 만들어도 되는가?"가 되겠네요.만약 이 경우에 AOP사용은 지양하는 것이 좋다고 생각하신다면, 매뉴얼하게 데코레이터 클래스를 작성하는 것 외에 권장하실만한 방법이 있을까요?
-
미해결스프링 핵심 원리 - 고급편
파이널으로 등록된 빈을 빼면 에러가 날 수 있다는게 어떤 의미일까요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]15분 00초부터 파이널 이런걸로 등록된 빈들도 있는데 이건 프록시로 못써서 빼면 에러날 수 있다고 하셨는데요.제가 이 말이 무슨 의미인지 이해를 못했습니다.파이널 클래스인 경우 cglib으로 상속 못받아서 프록시를 못 만들 수 있다는건 이해가 되는데, 빼면 에러가 난다는게 무슨 뜻인지 모르겠어요
-
미해결코딩으로 학습하는 GoF의 디자인 패턴
팩토리메소드 = 추상팩토리?
이 코드는 팩토리 메소드 패턴이고,public interface ShipFactory { Ship createShip(); } 이 코드는 추상 팩토리 패턴입니다.public interface ShipPartsFactory { Anchor createAnchor(); Wheel createWheel(); } 팩토리 메소드 패턴은 product와 createor간의 의존성을 낮추는것을 목적으로, 서브 클래스인 concreator에게 의존성을 위임합니다. 추상 팩토리 패턴은 여러 객체의 생성이 있을때 여러 객체의 의존성을 낮추기 위해, 마찬가지로 서브 클래스인 concreator에게 의존성을 위임합니다그렇다면 사실상 차이는 생성하는 객체의 수 뿐인데, 왜 다른 이름으로 만들었는지 이해가 안가네요..
-
해결됨은종쌤과 자바로 디자인 패턴 쉽게 시작하기
Bridge pattern 에서...
안녕하세요,Bridge 패턴에서 큐나 스택을 만들때 기능을 구현한 List를 상속하는데 상속받은 메소드를 써야하는거 아닌가요? 예를들어 add 나 remove 같은.public class Queue<T> extends List<T> { public Queue(AbstractList<T> list) { super(list); System.out.println("Queue"); } public void enQueue(T obj) { add(obj); } public T deQueue() { return remove(0); } }public class Stack<T> extends List<T> { public Stack(AbstractList<T> list) { super(list); System.out.println("Stack"); } public void push(T obj) { add(obj, 0); } public T pop() { return remove(0); } public T peek() { return get(0); } }
-
해결됨스프링 핵심 원리 - 고급편
ThreadLocal 관련하여 질문드립니다.
spring webflux에서 비동기 통신을 한다면한쓰레드에서 블록킹되지 않고 다른 프로세스가 진행되는 것으로 알고 있습니다.webflux에서 threadLocal을 쓴다면 한 thread를 점유하는 의미가 없는것인지 질문드립니다.
-
해결됨코딩으로 학습하는 GoF의 디자인 패턴
중재자 패턴에 관하여~
안녕하세요중재자 패턴을 공부하던 중에 궁금한 점이 있어서 질문하게되었습니다.1. 현재 강의에서는ConcreteMediator(FrontDesk)와 ColleagueA(Guest) , ColleagueB(CleaningService) ColleagueC(Restaurant) ... 이렇게 구성되는걸로 파악되는데현재 ConcreteMediator에 대한 인터페이스(Mediator)와 그 인터페이스를 참조하는 Colleague가 만들어 있지 않은데 굳이 만들지 않아도 괜찮은건가여?2.중재자 패턴을 ConcreteMediator에 모든 의존성을 다 가지게 만들어서 사용한다 라고 이해하면 되나요??
-
미해결스프링 핵심 원리 - 고급편
포인트컷과 어드바이스의 관계를 다음과 같이 이해하면 될까요?
프록시대리자를 통칭디자인 패턴프록시 패턴접근 제어캐싱(Caching), 지연 로딩(Lazy Loading)검증(Valid), 인증(Auth)데코레이터 패턴부가 기능로깅(Log)컨버터(Convertor), 포맷터(Formatter)스프링 프록시포인트 컷검증(Filter)만 담당어드바이스검증 이외의 모든 로직을 담당데코레이터 패턴 + 프록시 패턴(캐싱, 지연 로딩)어드바이저포인트 컷 1개 + 어드바이스 1개의 묶음위와 같이 이해하는게 맞게 이해하고 있는지 궁금합니다.
-
미해결스프링 핵심 원리 - 고급편
예시 코드가 실행하면 프록시로 등록이 안되네요ㅠㅠ
이 상태에서 계속해서 proxy로 ExamRepository랑 ExamService 가 proxy로 등록이 안돼서 로그 남기는 거랑 오류 복구 과정이 안됩니다 ㅠㅠ
-
미해결스프링 핵심 원리 - 고급편
쓰레드 로컬과 쓰레드 스택의 차이
동시성 문제를 해결하기 위해서 쓰레드 로컬이 각 쓰레드별 전용 저장공간을 만들어 데이터를 저장한다고 하셨는데 JVM의 메모리영역중에서 힙과 메소드영역은 모든 쓰레드가 공유하지만 각 쓰레드별로 스택공간이 할당된다고 알고 있습니다.그렇다면 쓰레드 로컬을 통해 데이터를 저장하면 각 쓰레드의 스택영역에 데이터가 저장되는 것인가요?만약 아니라면 쓰레드 로컬과 각 쓰레드의 스택영역에 저장되는 데이터들은 어떤 차이가 있는 것인지 궁금합니다.
-
미해결스프링 핵심 원리 - 고급편
@transaction
안녕하세요! 영한님 강의 정말 감사합니다!궁금한게있어요!그러면 Srping 에서 제공하는 트랜잭션이 default로 CGLIB 를 사용하는 것을 알겠습니다. 또한, 프록시 패턴을 통해서 inner method가 트랜잭션이 안탄다는것도 완벽 이해했습니다. ( self invocation )그럼 당연히 @Transactionalpublic void a () { // logic innerMethod()}private void innerMethod() {}와 같은 코드에서도 innerMetohd가 target 에 걸리는 바람에 트랜잭션이 끊기는 걸로 이해했는데요.맞나요!?
-
미해결코딩으로 학습하는 GoF의 디자인 패턴
undo 메소드 작업중에서
예를 들어 LightOffCommand 클래스에서 Light를 가지고 있는데 undo() {light.on();}이렇게 사용하지 않는건 단일책임 원칙때문에 그런건가요?
-
미해결스프링 핵심 원리 - 고급편
@Slf4j
@Slf4j 어노테이션 의미를 잘 모르겠습니다.현재로그추적기 부분에서 사용되는 부분에서요