묻고 답해요
130만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 핵심 원리 - 고급편
회원 유효성 검사에 AOP 를 적용해도 될까요?
안녕하세요 강사님 AOP 를 배우니, 개인 프로젝트에 적용하고 싶은 생각이 들어 질문을 드립니다. 현재 게시판 서비스를 개발중입니다. 이 때 탈퇴한 회원의 글이나, 숨김 처리된 글은 화면단에서 보이지 않도록, 게시글 조회 API 마다 "필터 로직"을 중복하여 사용하고 있습니다. 그렇다 보니, api 마다 중복되는 필터 로직을 AOP 로 대체할 수 있지 않을까 생각이 들었습니다. 학습 자료를 보니 "오류 검사 및 처리, 동기화, 성능 최적화, 모니터링/로깅" 에 AOP 가 사용된다고 적혀있는데, 제가 구현하고자하는 필터링 로직도 AOP 를 적용하는 것이 적절한지 궁금하여 질문 드립니다 감사합니다 ! 회원의 유효성 검사라는 횡단 관심사의 문제는 충족하지만, 이를 DB 단이 아닌 AOP 를 적용하여 해결하는 것이 적절한 방법인지에 대한 궁금증이라 생각해주시면 감사하겠습니다 :))
-
미해결스프링 핵심 원리 - 고급편
실행시간에 따른 log 레벨 적용
강사님께서 말씀주신 실행시간에 따른 log 레벨 적용해 보았습니다. 필요하신 부분 참고부탁 드립니다. (오류시에만 로그 남기는 부분은 @AfterThrowing을 사용하면 될것같습니다, - retry 에서 재시도 부분 제거) 1. 애노테이션 - 기본값 1000 @Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface CheckTime { int value() default 1000;} 2. Aspect @Around("@annotation(checkTime)")public void checkTimer(ProceedingJoinPoint joinPoint, CheckTime checkTime) throws Throwable { int mills = checkTime.value(); int maxMills = 4000; StopWatch stopWatch = new StopWatch(); stopWatch.start(); joinPoint.proceed(); stopWatch.stop(); long totalTimeMillis = stopWatch.getTotalTimeMillis(); Signature signature = joinPoint.getSignature(); String methodName = signature.getName(); if (totalTimeMillis <= mills) { log.info("methodName: {}, 실행시간 = {}ms", methodName, totalTimeMillis); } else if (totalTimeMillis <= maxMills) { log.warn("methodName: {}, 실행시간 = {}ms", methodName, totalTimeMillis); } else { log.error("methodName: {}, 실행시간 = {}ms", methodName, totalTimeMillis); }} 3. 애플리케이션 코드 - 랜덤으로 실행시간 적용 @CheckTime(value = 2000)public String save(String itemId) { seq++; if (seq % 5 == 0) { throw new IllegalStateException("예외 발생"); } sleep(); return "ok";}private void sleep() { int[] ints = {1000, 2000,3000,4000,5000}; double random= Math.random(); int num = (int) Math.round(random * (ints.length-1)); System.out.println(ints[num]); try { Thread.sleep(ints[num]); } catch (InterruptedException e) { e.printStackTrace(); }}
-
해결됨스프링 핵심 원리 - 고급편
강의 학습 중 공통(부가)기능 처리 방법에 대한 질문입니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 아니오2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요. 스프링 핵심원리 고급편에서 다루는 주요 내용인 핵심기능과 공통(부가)기능을 어떻게 나눌 것인가를 듣다보니 어느덧 AOP 챕터까지 다다르게 되었습니다. 강의를 통해 부가기능의 종류에는 크게 로깅, 트랜잭션처리, 접근권한확인이 있다고 생각이 들었습니다. 이것들은 앞에서 다룬 개발 패턴이나 AOP를 사용하지 않고도 유틸리티성 클래스를 통해 처리가 가능한 것으로도 알고 있지만 SOLID 원칙, 유지보수 효율 증대, 중복 코드 제거 등의 많은 이점을 가져다주기 때문에 AOP와 같은 기술을 사용하는 것은 이해를 했습니다. 그러나 Filter/HandlerInterceptor를 사용해서도 부가기능을 처리할 수 있을 것으로도 생각이 드는데요.(스프링 MVC 강의 학습을 통해 느낀 점입니다.) 저와 비슷한 생각을 가지고 계신 다른 분께서 질문한 글의 답변을 인용하자면 웹과 관련된 공통(부가)기능(특정 메뉴 접근권한 확인, 로그인 여부 확인 등)는 Filter/HandlerInterceptor를 통해 처리하고, 순수한 자바 코드를 통한 공통(부가)기능은 AOP를 이용하는 것이 맞는 것인지 궁금합니다. (참고 질문: https://www.inflearn.com/questions/495293) 물론 더 나아가 시큐리티를 알고 있다면 이런 질문 내용도 다른 방식으로 해결이 가능하겠지만, 만약, 시큐리티를 현재 모르고 있다라는 가정하에 위와 같이 실무에서도 처리하는게 맞는지 첨언 부탁드리겠습니다. 미리 답변 감사드립니다.
-
미해결스프링 핵심 원리 - 고급편
component 중복초기화 부분 추상클래스로 변경
강사님께서 말씀주신 component 중복 호출 부분 추상클래스로 빼봤습니다. 피드백 사항 있으면 말씀 부탁 드립니다^^; Decorator - 추상클래스 public abstract class Decorator implements Component{ private Component component; public Decorator(Component component) { this.component = component; } @Override public String operation() { return component.operation(); }} MessageDecorator public class MessageDecorator extends Decorator{ public MessageDecorator(Component component) { super(component); } @Override public String operation() { log.info("MessageDecorator 실행"); //data -> *****data***** String result = super.operation(); String decoResult = "*****" + result + "*****"; log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후={}", result, decoResult); return decoResult; }} TimeDecoratior public class MessageDecorator extends Decorator{ public MessageDecorator(Component component) { super(component); } @Override public String operation() { log.info("MessageDecorator 실행"); //data -> *****data***** String result = super.operation(); String decoResult = "*****" + result + "*****"; log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후={}", result, decoResult); return decoResult; }} test 코드 @Testvoid decorator3() { Decorator messageDecorator = new MessageDecorator(new RealComponent()); messageDecorator.operation(); System.out.println(); Decorator timeMsgDecorator = new TimeDecorator(new MessageDecorator(new RealComponent())); timeMsgDecorator.operation();}
-
미해결스프링 핵심 원리 - 고급편
실무에서 몇 개 정도의 어떤 어즈바이저를 적용해서 사용중인가요?
영한님, 안녕하세요. DB접근기술 강의를 듣고나니, 스프링 핵심원리 강의들이 다시 떠올라서 핵심원리 복습을 하고 있습니다. 스프링 AOP 에서 여러 어드바이저를 적용해도 프록시는 하나만 생성되어 사용된다 라고 콕 찝어서 설명을 해주셨는데요. 혹시 소속되어 계신 배민이나 그 전에 경험하신 시스템에서 주로 몇 개 정도의 어드바이저를 적용했고, 대략 어떤 부가기능들이 적용되어 있었는지 알 수 있으면 좋겠습니다. (참고용으로요) 로강을 위해 데이터베이스에 정보를 기록하는 부가기능들도 본 적이 있는데, 이런 부가기능들이 모이면 시스템 성능에 영향을 줄 수 있을텐데요. 보통 성능에 문제가 생길까봐 AOP 등록을 해도 될 지 고민되는 경우가 많은데 이를 어떻게 판단할 수 있을까요? 너무 애매한 질문을 드린 건 아닌가 모르겠네요. 작은 도움될만한 정도라도 답변을 주시면 감사하겠습니다.
-
해결됨코딩으로 학습하는 GoF의 디자인 패턴
Flyweight Pattern 이론 강의 자료중에 오타인거 같습니다.
Flyweight Pattern 이론 강의 자료 중에 내적인 요소, 외적인 요소의 영어 표현으로 [Intrinsit], [extrinsit] 라는 표현이 있는데 해당 표현들은 [Intrinsic], [extrinsic] 표현인거 같습니다. 혹시 오타이신건가요? 항상 좋은 강의 감사드립니다.
-
미해결스프링 핵심 원리 - 고급편
Thread local 과 Prototype bean 문의
안녕하세요 강의 감사히 잘 듣고있습니다. 이게 Request Scope 하고도 비슷한 답변일거같긴한데.. 혹시, Prototype bean 으로도 해당문제를 해결할수 있지않나요?? 무슨기준으로 어떤때는 Prototype bean 을사용하고 어떤때는 Thread local 을가지고 사용하는지가궁금합니다.
-
미해결스프링 핵심 원리 - 고급편
private method 포함한 Controller @Aspect로 AOP 적용했을때의 의문점
안녕하세요. Controller에 AOP를 적용하는 과정에서 궁금한점이 있어 질문을 올립니다. 보통 handler method 는 private 으로 지정하진 않겠지만, 만일 private으로 지정해도 handler는 정상 동작하는 것으로 알고 있고 정상 동작도 확인하였습니다. 그런데, @Aspect 이용해서 해당 Controller의 Proxy를 빈으로 등록시켰을때 문제가 발생합니다. 우선, 첫번째 예상했던 것은 CGLIB는 상속을 이용하기에 private메서드는 상속을 못해서 handler가 정상동작하지 못할 것 같았습니다. 하지만 결과는 정상동작하는 것을 보았습니다. 어떻게 정상동작이 수행가능 한걸까요? 혹시, private handler의 경우는 바로 target메서드를 찾아 실행시키나 해서 stack trace를 봐보면 Enhancer객체에서 실행되는 것을 볼 수 있습니다. 물론, 이처럼 간단한 handler라면, 정상적으로 응답이 오지만 만일 해당 handler가 의존성주입된 객체를 사용하려고 한다면 Enhancer 객체는 상태를 갖지않는 proxy객체라 NullPointerException이 발생합니다. 의문점을 정리해보자면, `private handler는 어떻게 Enhancer객체에서 수행할 수 있을까? ` 입니다. 한번 reflection은 private메서드도 수행가능하기에 상속한 슈퍼클래스의 private 메서드를 이용해 정상 동작한다. 로 가정하고 생각해봤습니다. 그러면 또 꼬리의문이 드는데 슈퍼클래스의 private메서드를 이용한다면, 실제 target 메서드이므로 DI된 객체가 null이 되는 것이 의문 입니다.
-
미해결스프링 핵심 원리 - 고급편
createNextId() 메서드에서 항상 새로운 객체를 생성하는 이유가 궁금합니다.
항상 영한선생님 강의 정말 잘 보고 있습니다. 그런데 제가 지식이 부족하여 질문을 하나 올립니다. 5분30초 쯤에 만드는 createNextId()메서드에서 항상 레벨에 1을 더해서 새로운 TraceId를 반환하는데 처음에 만들어진 객체에 1을 계속 더해서 갖고가는 것이 아니라 계속 새로운 객체를 생성하는 이유가 궁금합니다.
-
미해결스프링 핵심 원리 - 고급편
포인트컷 지시자 단독 사용 관련해서 질문 있습니다.
args, @target 등은 실제 객체 인스턴스가 생성되고 실행될 때 어드바이스 적용 여부를 확인할 수 있다는 부분이 잘 이해가 가지 않습니다. 빈 후처리기에서 빈으로 넘어오는 클래스의 메소드 정보를 보면 args랑 매칭시킬수 있을것 같고 @target도 빈으로 넘어오는 클래스를 상속한 자손클래스에서 특정 애노테이션이 있는지 여부를 확인하면 프록시 적용 여부를 판단 할 수 있을것 같은데... 왜 무조건 프록시를 만들어 놓고 런닝타임에 객체 인스턴스가 넘어와야 어드바이스 적용 여부를 판단 할 수 있는것인지 궁금합니다!! 답 주시면 감사하겠습니다!
-
미해결스프링 핵심 원리 - 고급편
질문있습니다.. 리플렉션 강의 설명중 람다를 사용하는 상황에 대해
[질문 내용]안녕하세요. 강의 잘 듣고있습니다~~ 다름아니라 리플랙션 강의 내용중 람다를 사용해서 공통화하는것도 가능하다 하셨는데요, 람다의 어떤 특징때문에 이루어 지는지 궁금합니다. 나름대로 생각해봤는데 함수형프로그래밍 (매개변수에 함수로직을 넣을수있는)개념을 써서 공통화 시키는게 맞는지 궁금합니다. 또는 리플랙션 처럼 람다 역시 런타임에 동적으로 클래스를 정의되고 그 인스턴스를 생성해서 반환하는 특성을 의미하신건가요? 질문이 어려우실수도 있는데 실마리라도 주시면 감사하겠습니다. ^^ ================= 답을 찾은것 같습니다. 혹시 저와 같은 궁금증을 가진분을 위해 남겨놓겠습니다.
-
미해결스프링 핵심 원리 - 고급편
@target 의 정의에 대해 질문이 있습니다.
안녕하세요 강사님 이번 강의에서 언급하신 `@target 어노테이션`의 정의에 대해 제가 제대로 이해했는지 궁금하여 질문 남깁니다. @target 은 인스턴스의 모든 메서드를 조인 포인트로 적용하기 때문에, target 의 대상인 `ClassAop`어노테이션이 붙은 Child 클래스만 target 의 대상이라 생각했습니다. Child 클래스의 `인스턴스`는 Child 클래스로부터 생성된 객체만을 의미하는데, 이 객체는 Parent 로부터 상속을 받았습니다. 그래서 Child에 현재는 Parent 의 메소드가 구현 돼있지 않지만, 나중에라도 구현할 수 있기 때문에 "부모의 메서드도 @Target 의 대상이 되는 것" 이라고 이해했습니다. 결국 상속의 특성으로 인해 @Target 이 부모메서드에도 적용되는 것인가요? 좋은 강의 만들어주셔서 늘 감사합니다!
-
해결됨스프링 핵심 원리 - 고급편
이번 예제에서 Config 클래스에 @Configuration 을 적용하니, Proxy 래핑/등록이 안되는것 같습니다.
강사님 안녕하세요.저는 지금 예제 구현시 의도와 다르게 약간 틀린 설정으로 생긴예상밖의 결과로 약간 혼동을 겪고있습니다. 이유는 @Configuration 을 실수로 붙였더니, 아래와 같이Proxy 가 적용되지 않은 결과가 나옵니다. Config 클래스에 아래와 같이 @Configuration 선언시 @Configurationstatic class Config { ... ...} child.childMethod(); 실행 후 로그 메세지: child Proxy=class ...AtTargetAtWithinTest$Child(Proxy 적용이 안된 스프링 빈 출력) child.parentMethod(); Parent 는 프록시 처리가 되지 않아 출력되지 않음 관례처럼 사용해오던 @Configuration 을 지우니 강의 예제결과처럼 정상으로 나옵니다.(@Import 를 통해 Config 추가 상태) Aspect 를 빈으로 등록해도 Proxy 변환이 안되는 이 상황이 이해가 되지 않아 부득이하게 질문을 남기게 되었습니다. 질문입니다. 예전 강의에서 @Configuration 은 등록되는 빈 을 대상으로 싱글톤 후처리를 위해 선언되는 것이라 알고있었습니다.( CGLIB 을 통해 프록시 후처리), 그래서 Aspect 가 당연히 적용될 줄 알았는데 @Configuration 을 붙이니,Proxy 처리가 되지 않더라구요. 아래는 두가지 결과 입니다. @Configration Config @Import(Config.class) @Configuration 선언 시, Proxy 후처리가 되지 않는 기묘한 현상에 대한 이해가 잘 되지 않습니다.이런 이유로 Config 클래스에 @Configuration 을 쓰지않고, @Import 로 추가하신 이유가 궁금합니다. 읽어주셔서 감사드립니다.
-
미해결스프링 핵심 원리 - 고급편
@Aspect 안에 여러 어드바이스 작성 시, 어드바이저는 어떻게 구성이 되나요?
안녕하세요! 항상 좋은 강의 및 답변주셔서 감사합니다. 강의를 듣고 복습하던 도중 한 가지 궁금한 부분이 있어 글을 작성하게 되었습니다. @Aspect@Slf4jpublic class AspectV2 { @Pointcut("execution(* hello.aop..*.*(..))") public void allOrder(){} // public java.lang.String hello.aop.order.OrderRepository.save(java.lang.String) @Around("allOrder()") public Object doLog1(ProceedingJoinPoint joinPoint) throws Throwable { log.info("[log] {}", joinPoint.getSignature()); return joinPoint.proceed(); } @Around("allOrder()") public Object doLog2(ProceedingJoinPoint joinPoint) throws Throwable { log.info("[log] {}", joinPoint.getSignature()); return joinPoint.proceed(); }} 위의 코드에서 어드바이저는 총 몇개가 생기는지 궁금합니다. @Aspect가 있는 빈이 생길 경우, AutoProxyCreator가 @Aspect를 읽고 어드바이저를 작성해서 @Aspect Advisor 빌더 내부에 저장해두는 것으로 알려주셨는데요... 위의 코드가 실행되면, 어드바이저는 2개가 되는 걸까요? 아니면 1개만 되는 걸까요? 제가 이해하기로는 어드바이저는 주로 Default Advisor를 사용해서 1포인트컷 + 1어드바이저로 구성된다고 이해를 해서 2개가 생길 것으로 생각되긴 한데... 항상 좋은 강의 및 답변 해주셔서 고맙습니다. 감사합니다!
-
미해결스프링 핵심 원리 - 고급편
this 질문드립니다.
안녕하세요. 강의를 듣다가 궁금증이 생겨 질문드립니다. 이전 강의에서 프록시가 생성되는 과정을 보면 1. @Aspect 애노테이션을 클래스에 선언하고 클래스 안에 @Around로 포인트컷 표현식을 정의하고, @Around가 붙은 메서드로 이제 어드바이스를 정의 2. 스프링 애플리케이션이 초기화 될 때 자동프록시생성기가 @Aspect가 붙은 클래스를 다 찾아서 어드바이저생성 3. 이제 스프링 빈으로 등록될 객체들을 하나씩 불러와서 어드바이저의 포인트컷을 통해 프록시 대상인지 아닌지 확인해서 프록시를 생성하여 스프링 빈으로 등록 으로 이해를 하였는데요. 이번 강의에서 @Aspect 클래스 안에 메서드에 @Around("this(hello.aop.member.MemberService)") 이런식으로 this에 타입을 정의하는데, 초기화 시점에 스프링 빈 대상 객체들을 this 포인트컷 표현식으로 프록시 대상 객체인지 아닌지 확인할 수가 없지 않나요? 왜냐하면 아직 프록시가 생성되기 전인데 어떻게 this(프록시 객체)을 판단할수가 있는건가요? 아니면 모든 빈을 일단 프록시로 만들고 실행시점에 판단하는 방식인가요? 감사합니다.
-
미해결스프링 핵심 원리 - 고급편
Pointcuts 클래스를 빈으로 등록 안한 이유
Pointcust 클래스를 빈으로 등록하니깐 @Around("Pointcuts.allOrder()") 이렇게 해도 되는데 왜 강의에서는 경로를 지정해서 한건가요? 둘이 어떤 차이점이 있는건가요?
-
미해결스프링 핵심 원리 - 고급편
구체 클래스 기반 프록시 예제2
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (아니오)[질문 내용 : 2분11초~] 이 케이스에서는 TimeProxy가 ConcreteLogic를 상속했기 때문에 이미 ConcreteLogic에 대한 정보(super)를 갖고 있는 것으로 보이는데, 멤버변수에 ConcreteLogic를 추가하신 의도가 있으신 건가요? 인터페이스를 사용할 때에는 손뼉을 쳤지만 구체 클래스 기반 프록시를 보니까 갑자기 위화감이 들어서 질문 드립니다....
-
해결됨코딩으로 학습하는 GoF의 디자인 패턴
싱글톤에서 Early, Lazy 초기화의 차이
안녕하세요. 싱글톤에서 Early, Lazy 초기화의 차이를 공부하기 위해 클래스 로드에 개념을 처음으로 딥하게 공부해보고 있습니다.클래스 로드와 사용에 따른 초기화간 heap 메모리 할당이 되는지도 공부하기 위해 위와 같이 트래킹해봤습니다. 저는 트래킹 결과를 보고 아래와 같이 해석했습니다. 1. 사용하지 않으면 early, lazy 모두 초기화되지 않는다.2. early 는 getInstance() 메소드로 진입할 때 초기화 된다. lazy 는 getInstance() 메소드가 끝날 때 Holder 를 통해 초기화 된다. 하지만 강의에는 early 초기화시 사용하지 않아도 생성된다고 말씀해주셨습니다. 그렇다면 캡쳐 1에서 인스턴스가 보여야된다고 생각했는데 보이지 않아 혼동이 와서 질문 드립니다. 혹시 제가 개념이 헷갈리거나 트래킹을 잘못하고 있는 것일까요..? ㅠㅠ public class App { public static void main(final String[] args) { singleton(); } private static void singleton() { final EarlyInitializationSingleton early = EarlyInitializationSingleton.getInstance(); // 캡쳐 1 final LazyInitializationSingleton lazy = LazyInitializationSingleton.getInstance(); // 캡쳐 3 System.out.println("end"); // 캡쳐 5 }} public class EarlyInitializationSingleton { private static final EarlyInitializationSingleton INSTANCE = new EarlyInitializationSingleton(); private EarlyInitializationSingleton() { } public static EarlyInitializationSingleton getInstance() { return INSTANCE; // 캡쳐 2 }} public class LazyInitializationSingleton { private LazyInitializationSingleton() { } private static class LazyInitializationSingletonHolder { private static final LazyInitializationSingleton INSTANCE = new LazyInitializationSingleton(); } public static LazyInitializationSingleton getInstance() { return LazyInitializationSingletonHolder.INSTANCE; // 캡쳐 4 }}
-
해결됨코딩으로 학습하는 GoF의 디자인 패턴
enum 객체는 멀티쓰레드 환경에서 안전한가요?
안녕하세요. 기선님. 좋은 강의 감사합니다. 이번 수업을 들으면서 궁금한 점이 생겨 질문 남깁니다. 1:34초쯤 Settings enum 클래스에 number 필드 및 게터 세터를 생성하셨는데, 이러한 상황에서도 동기화 블록없이 커스터마이징된 enum 객체가 쓰레드-세이프한건가요? 답변 부탁드립니다. 감사합니다.
-
해결됨코딩으로 학습하는 GoF의 디자인 패턴
블로깅할 때 주의점 & 강의 장표의 질문들의 답
안녕하세요. 싱글톤 하나만 들었는데도 안일하게 사용하고 있던 지식들이 채워지는 너무너무 좋은 강의입니다. 강의를 들으면서 공부하는 데 질문이 있어 남깁니다. --- 1. 저는 공부하는 자료에 대해서 가능하면 블로깅을 남기고 있습니다. 남에게 설명할 수 있는 수준이 되어야만 진정으로 이해하는 것이라고 생각하기 때문입니다. 혹시 강의 내용을 블로깅하는데 있어 제약사항이 있을까요? ex) - 강의 장표 캡쳐 불가 - 강의 장표의 질문 노출 불가 2. 동영상 뿐만이 아니라 강의 장표에 많은 질문들로 한번 더 생각할 기회를 주시는 것 같아 너무너무 감사합니다. 물론 제가 먼저 찾고 공부하는 것이 우선이지만, 제가 답을 냈을 때 비교를 할 수 있는 답이 있으면 더 좋을 것 같은데 혹시 공개되어 있을까요? 다시 한번 좋은 강의 너무너무 감사합니다!!!!