Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[톰캣 구현하기 3 & 4단계] 홍고(홍여진) 미션 제출합니다 #483

Merged
merged 17 commits into from
Sep 13, 2023

Conversation

hgo641
Copy link

@hgo641 hgo641 commented Sep 11, 2023

안녕하세요, 포이!
너......무......... 부족한 코드지만 잘 부탁드립니다ㅠㅠ
테스트도 이번에 완성해오겠다고 했는데 약속을 지키지 못해 죄송합니다

변경된 부분은 크게 두 가지 있습니다!

  • HandlerMapper내부의 메소드들을 Cotroller인터페이스의 구현체로 변경
  • 파일을 읽는 StaticFile 클래스 생성

@hgo641 hgo641 requested a review from poi1649 September 12, 2023 02:13
@hgo641 hgo641 self-assigned this Sep 12, 2023
Copy link

@poi1649 poi1649 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홍고 안녕하세요! 전체적으로 패키지 분리를 열심히 해주신게 굉장히 눈에 띄네요! 특히 HandlerMapper 가 ServletContainer 처럼 활용되도록 설정하여 의존을 끊어주신 부분이 인상깊었습니다!

새로운 미션도 진행되고 할 일이 엄청 많으실 것 같아 머지를 할까 고민했는데요.. 특정 부분에서 의도하신대로 작동하지 않는 코드일 수 있을 것 같아 한 번은 리퀘스트 체인지 남깁니다! 혹시 제가 홍고의 의도를 잘못이해한거라면 수정하지 않으시고 커멘트로 내용만 공유해주시면 감사하겠습니다! 오늘도 좋은 하루 보내세요!

protected void doPost(final Request request, final Response response) {
final Map<String, String> requestForms = request.getRequestForms().getFormData();
final Optional<User> user = login(requestForms.get(ACCOUNT), requestForms.get(PASSWORD));
if (user.isPresent()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 isPresentOrElse() 대신 if 분기문으로 처리해주신 이유가 있나용?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ifPresentOrElse() 가 있는지 몰랐네요!!! 적용했습니다 코드가 깔끔해졌네요! 👍


@Override
protected void doGet(final Request request, final Response response) throws Exception {
if (request.getSessionValue(USER) != Optional.empty()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request.getSessionValue(USER).isEmpty() 처럼 옵셔널 내부 메서드로 검사해주는게 더 옵셔널스럽게 사용하는 방법 같네요! 그러면 null 비교에 비해 이점을 확실하게 가져갈 수 있을 것 같아요😎

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request.getSessionValue(USER).isEmpty() 너무 좋아요~~~ 다른 Optional들도 동일하게 수정했습니다!


@Override
protected void doPost(final Request request, final Response response) throws Exception {
throw new UnsupportedRequestException();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커스텀 예외 멋지네요👍

Comment on lines +21 to +24
protected void doGet(final Request request, final Response response) throws Exception {
final Response createdResponse = Response.createByResponseBody(HttpStatus.OK,
new ResponseBody(ROOT_MESSAGE, ContentType.HTML));
response.setBy(createdResponse);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setBody, setStatus 대신 response 객체 자체를 새로 만들어주신 이유를 공유해주실 수 있나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 유효한 정보(status, body)들을 받아 Response를 생성해주는 로직이 존재했는데, 3단계 요구사항에서 doGet(final Request request, final Response response) 메소드가 생기면서 Response를 무조건 디폴트값으로 초기화하게 되었습니다.
기존에 생성한 유효한 정보(status, body)들을 받아 Response를 생성해주는 로직을 그대로 재활용하기 위해 setBy()를 생성했습니다...ㅎㅎ

물론 사용하지 않을 복사용 Response 객체가 생기긴 하지만...ㅎㅎ 이 정도는 괜찮지 않을까 했어요...ㅎㅎ
혹시 마음에 걸리는 부분이 있으신가요?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 큰 차이는 없다고 생각하는데 혹시 제가 생각못한 장단점이 있을까해서 여쭤봤습니다! 🫡

일반적인 서블릿 프로그래밍과 약간의 차이가 있다면 공통 헤더를 처리해주는 filter들을 따로 두어 doFilter 메서드로 리스폰스에 필요한 것들을 계속해서 set해주는 과정으로 가져가는 것 정도 같네요!

Comment on lines 43 to 47
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
this.handlerMapper = handlerMapper;
this.controllerMapper = controllerMapper;
this.executorService = Executors.newFixedThreadPool(maxThreads);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executors 클래스로 파일을 스레드풀을 생성하게되면 unbounded한 작업 큐가 생성되어 의도하신대로 100개의 작업만 대기시킬수는 없을 것 같네요! accept count 를 활용해 100개의 작업을 대기시키려면 다른 방법을 써야할 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 그렇네요! 스레드 고수 포이 감사합니다!!
new ThreadPoolExecutor를 사용해서 queue의 사이즈를 100으로 지정해주었습니다!

Copy link

@poi1649 poi1649 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 queue 를 사용하셨군요. 구구는 Executors 안의 메서드를 사용해서 만들어보라고 하셨지만 저도 이 방법이 제일 속편한 것 같아요ㅋㅋㅋㅋ.. ....

그런데 사실 현재 구조라면 socket의 accept-count 수 만큼 백로그에서 추가로 더 대기하게 됩니다. 스레드 작업큐 100개 + 백로그 100개 총 200개의 커넥션이 대기하게 되겠네요.
또, 두 가지 영역을 함께 사용하면 관리도 번거로워질 수 있어요!
백로그에 있는 커넥션은 타임아웃시 계속 재전송을 요청(tcp의 기능)하는 반면, 스레드에 있는 커넥션은 어플리케이션 로직에 따라 다르게 처리됩니다.

}

public void stop() {
stopped = true;
try {
serverSocket.close();
} catch (IOException e) {
executorService.shutdown();
Copy link

@poi1649 poi1649 Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오.. shutdown 꼼꼼하시군요! 혹시 awaitTermination 말고 shutdown만 쓰신 이유를 여쭤볼 수 있을까요?

Copy link
Author

@hgo641 hgo641 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awaitTermination에 대해 알지 못했습니다ㅠㅠ shutdown만 하면 task가 종료되기도 전에 shutdown을 호출한 메인 스레드가 먼저 종료될 수도 있겠군요. awaitTermination을 함께 사용해서 task가 종료되는 것을 60초동안 기다리게 변경했습니다!
+ InterruptedException처리도 해주는 게 좋다고 해서 추가했습니다!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍 쓰레드는 신경쓸게 참 많은 것 같아요 ㅋㅋㅋㅋ

final URL url = classLoader.getResource(STATIC_ROOT_PATH + path);
try {
return new String(Files.readAllBytes(new File(url.getFile()).toPath()));
} catch (final NullPointerException e) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFile() 을 사용하면 없는 경로의 경우 emptyString을 반환하고, new File 에서 빈 문자열이 들어오면 새로운 파일을 반환한다고 하네요. 이 경우 NPE가 발생하지 않을 것 같아요. files.exist() 라는 메서드가 있던 것 같은데 해당 메서드를 활용해봐야할 것 같기도 해요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

classLoader.getResource()에서 리소스가 존재하지 않으면 url이 Null로 할당됩니다!
Null.getFile()이 되면서 NPE가 발생하더라고요.

return new String(Files.readAllBytes(new File(url.getFile()).toPath())); 에서 catch를 하고 있어 로직을 파악하기 힘들 것 같네요! url이 null이면 new File까지 가지 않고 바로 예외를 반환하게 변경하겠습니다. 감사합니다!!

Copy link

@poi1649 poi1649 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 위 classLoader에서 먼저 null 을 반환하는군요 혼란을 드려 죄송합니다 ㅋㅋㅋㅋㅋ...🙇‍♂️

  • 확실히 수정하신 로직이 더 좋아보이긴 하네요!


public class SessionManager {

private static final Map<String, Session> SESSIONS = new ConcurrentHashMap<>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://google.github.io/styleguide/javaguide.html#s5.2.4-constant-names

저도 구구의 리뷰에서 발견한건데 구글 스타일 컨벤션에서 deeply Immutable 해야만 상수라고 설명하고 있네요. 조금 생각해보셔도 좋아보입니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

갸아악 감사합니다

@sonarcloud
Copy link

sonarcloud bot commented Sep 13, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 9 Code Smells

0.0% 0.0% Coverage
0.0% 0.0% Duplication

warning The version of Java (11.0.20.1) you have used to run this analysis is deprecated and we will stop accepting it soon. Please update to at least Java 17.
Read more here

Copy link

@poi1649 poi1649 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홍고 안녕하세요! 이것저것 바쁘실텐데 고생많으셨습니다. 🫡
이번 미션은 이만 머지해도 괜찮을 것 같아요!
정말 마지막으로 조금의 커멘트를 남겼는데 시간나실때 편하게 확인해주시면 감사하겠습니다!
다음 미션도 화이팅입니다!!

@poi1649 poi1649 merged commit fed4fdc into woowacourse:hgo641 Sep 13, 2023
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants