작성
·
271
0
답변 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 들으면서 한번 작성해보도록 하겠습니다!