생각해볼 문제에 대한 제 생각입니다. 피드백 부탁드려도될까요?

21.07.16 00:07 작성 조회수 158

0

- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
1. 캡슐화를 위해서라고 생각합니다.
2. 이 부분을 제일 많이 고민했습니다.
자바8이 들면서 default 메서드까지 사용이 가능해지고, 상속보다 합성을 많이 사용하고 인터페이스를 자주사용하라는 얘기를 많이 들었습니다.
제가 처음에 생각했을 때는 Seralizeable 구현에 대한 문제와 serialVersionUID에 대한 값을 들고있어야하는 문제때문이라고만 생각했습니다.

실제 인터페이스를 구현해서 따라가본 결과 다른 문제가 또 있었네요.

바로, 저희가 구현한 BoxContext 내부에서 쓰레드로컬에 set할 떄
기존 코드에서는 BoxLocal과 BoxHttp에 분기를 태워서 실제 WAS 로딩시점에서는 BoxHttp가 쓰레드에 올라가고, 아닐 경우에는 BoxLocal이 올라가는데 이 두개를 처리하는 것을 인터페이스로 할 수 없음을 알게 되었습니다.

즉, 마스터 컨트롤러에서 ThreadLocal에 적재를 할 때 상속으로 처리하지 않을 경우 컨트롤러에서 로직을 작성하여 이 경우에는 BoxLocal을 올리고, 아닐 경우에는 BoxHttp를 올리는 식으로 작업하게 되므로, 오히려 컨트롤러에 비즈니스 로직이 담기는 문제가 있다고 생각하게 됐습니다.

이 부분이 맞을지 궁금하네요 ㅎㅎ;

3. AOP 어노테이션은 가독성과 편리성 부여해줄 수 있다고 생각합니다.
@Transactional 과 같은 어노테이션을 살펴보자면 원래는 try-catch로 TransactionManager를 처리하는 방식에서 @Transactional의 어노테이션을 붙여두면 명시적으로 이러한 try-catch의 중복되는 구문 없이 사용되는 것에서 생각하게 됩니다.

뿐만 아니라 @Slf4j도 logger를 일일히 설정해서 중복되는 코드가 발생할 수 있는 부분을 어노테이션으로 단순화 시켜서 가독성과 편리성을 부여했다고 생각합니다.

4. 이 부분이 제일 어려웠던 고민이였던 것 같습니다.
제 생각에는 톰캣의 동작원리는 ThreadPool을 생성하여 미리 쓰레드를 사용하고 생성하는 것을 알고 있습니다. 이 때문에 ThreadLocal은 GC의 대상이 안되므로 maxThreads 의 값이 넘어가면 뻗거나 혹은 문제가 생길거 같은데
이 부분은 제가 정확하게 몰라서 궁금한 부분이기도 합니다.

TheadPool을 제가 잘 몰라서 그러는데 TheadPool에 쓰레드를 미리 만들어 두기 때문에 LocalThread 해제를 안할 시에 기존에 사용했던 쓰레드를 다시 재사용할 수 있으므로 이러한 문제가 있다고 생각해도 될까요?


답변 2

·

답변을 작성해보세요.

1

안녕하세요. 제로입니다.

처음으로 생각해볼 문제의 답을 적어 주셔서 감사합니다.


글을 적는건 남에게 지식을 전달하는 것도 있지만
내 지식을 깊게 생각하는데 도움이 되는 측면도 큰것 같습니다.

그런 면에서 깊게 생각한 모습이 보여
문제를 만든 입장에서 감사하다는 이야기를 드리고 싶습니다.

적어주신 내용 잘 봤구요.
제가 의도한 답은 아니지만 맞게 잘 설명해주셨습니다.

제가 의도한 답은 아래와 같습니다.

1. BoxContext.setThread() 와 BoxContext.removeThread() 의 접근제한자는 디폴트 입니다. 이유를 생각해보세요. (디폴트 접근자는 같은 패키지에서만 사용이 가능하다는


캡슐화는 메소드와 데이터가 하나의 모듈로 묶인걸 의미하고
정보은닉은 캡슐화로 묶인 데이터와 메소드중 필요한것 만 공개한다는 의미입니다.


개발자의 코드에서 
공통기능으로 제공되는 Box 의 생명주기를 제어하는 
BoxContext.setThread(), BoxContext.removeThread() 기능이 호출되면


의도한 프레임워크의 동작 흐름은 엉망이 되기 때문에
프레임워크 코드에서만 사용할 수 있도록
접근제한자를 디폴트로 설정했습니다.


많은 개발자들이 메소드를 만들때 public 을 습관적으로 부여하는데
public 이 아닌 디폴트로 접근제한자를 설정하고
필요할때 public 으로 공개했으면 합니다.



2. Box 는 추상화 클래스입니다. 인터페이스로 만들지 않은 이유에 대해 생각해보세요.


BoxLocal 과 BoxHttp 에서 사용될 공통 코드를 보관하기 위해
Box 를 추상화 클래스로 만들었습니다.


인터페이스는 기능의 틀을 표현하고
그 틀에 맞게 여러개의 클래스를 만든 뒤 
그중 하나의 클래스를 선택 객체로 사용할 때 효과적이지만


가장 큰 문제인 기능을 구현하기 위한 코드가 중복된다는 문제가 있습니다.

이런 공통코드를 해결하기 위해
유틸클래스를 만들거나 defualt 메소드를 사용하는 노력을 하는데


유틸클래스로 발생되는 코드의 복잡성
객체지향적이지 않은 defualt 메소드의 한계가 있어


인터페이스의 장점인 교체의 비용을 줄임과 동시에
(말씀하신 BoxHttp 와 BoxLocal 이 실행시점에 둘중 하나가 결정되어 사용)
공통기능을 객체지향적으로 쉽게 제공할 수 있는
추상화 클래스로 Box 를 만들었습니다.



3. AOP 를 구현할때 어노테이션은 어떤 역할을 하는지 생각해보세요.


어노테이션은 개발자가 만든 코드의 추가 정보를 기능으로 제공하는 메타데이터 입니다.
AOP 는 개발자에게 필요한 공통기능을 컴파일 없이 쉽게 사용할 수 있게 해주는 프로그래밍 기법이구요.

그런 관점으로 어노테이션의 역할을 생각해 보면
말씀하신 대로 필요한 공통기능을 (@Transactional, @Slf4j 등)
코드가 아닌 메타로 표현하고

프레임워크는 코드가 아닌 메타를 읽어 컴파일 없이 
트랜잭션이나 로그 기능을 동적언어처럼 제공한다고 생각하시면 됩니다.

그런데 어노테이션은 아주 큰 단점이 있습니다.

컴파일 없이 원하는 AOP 기능을 사용할 수 있다고 하지만
컴파일과 똑같은 배포 비용이 들어간다는 점입니다.

쉽게 말해서 수정된 코드가 이관(운영환경에 복사)되어야지만 의도한 코드가 동작한다는 것이죠.

그래서 우리가 만드는 프레임워크는 어노테이션 사용을 최소화 합니다.
이부분을 이야기 하기 위한 질문이었습니다. 



4. WAS 는 멀티쓰레드 환경에서 사용자 요청을 동시에 처리합니다. 만약 MasterController.service() 메소드에 있는 BoxContext.removeThread(); 기능이 실행 안되었을경우 발생하는 문제점에 대해 생각해보세요.


java 는 가비지컬랙션이라는 효과적인 메모리 관리 기법을 사용합니다.
가비지컬랙션이 되는 객체는 더이상 사용하지 않는 객체가 대상이 되는데
쉽게 말해 종료된 코드에 사용된 객체를 의미합니다.


그런데 Box 객체를 더 이상 사용되지 않는다고 선언하는
BoxContext.removeThread(); 기능이 실행하지 않아도

힙(객체가보관되는 메모리)영역의 아웃오브메모리 문제는 발생하지 않습니다.

바로 다른 요청을 처리하기 위해 선택되어 실행되는 쓰레드에서 
사용하는 BoxContext.setThread(new BoxHttp(request)) 메소드 때문이죠.

BoxContext.setThread 기능이 실행되는 순간
기존 남아 있던 Box 객체는 더이상 사용할 수 없는 객체로 판정되고
가비지 컬랙션 대상으로 포함 자동으로 회수되기 때문에 메모리 문제는 발생하지 않습니다.


그런데 BoxContext.removeThread() 가 실행되지  않았을 경우 발생되는 문제는
다른데 있습니다.

바로 MasterController.service() 메소드를 사용하지 않는
독립적인 요청에서 문제가 발생합니다.
(예: jsp 직접호출)


그 요청을 처리하기 위한 쓰레드에는 아직 Box 객체가 남아 있고
요청을 처리하기 위한 코드중 
BoxContext.getThread() 를 사용하는 순간
개발자가 의도한 객체인 BoxLocal  이 아닌
이전 요청 처에 사용된 BoxHttp 가 반환됩니다.

의도하지 않은 서비스 실행 결과가 된다는 것이죠.

난이도가 높은 질문이긴 하지만

이문제를 확인하기 위해

실제 테스트 할 수 있는 코드를 만들어 확인해 보시면
멀티스레드 그리고 WAS 의 병행/병렬처리 흐름을 이해하시는데 도움이 되는 질문이었습니다.

0

매우 친절한 답변 감사드립니다 ㅎㅎ

4번과 같은 경우는 직접 테스트 케이스를 만들어서 체감을 해봐야겠네요.

아 그리고 몰랐는데 섹션 1에도 몰랐는데 생각해볼 문제 파트가 존재했었네요;; 몰랐었는데 이 부분도 주말에 섹션 3 들으면서 한번 작성해보도록 하겠습니다!