소개
교육자
전: 우아한형제들 기술이사, 카카오, SK플래닛
진짜 실무에 필요한 제대로 된 개발자가 될 수 있도록, 교육하는 것이 저의 목표입니다.
저의 개발 인생 이야기
EO 인터뷰 영상
개발바닥 - 시골 청년 개발왕 되다
취업과 이직에 대한 고민 해결
강의
로드맵
전체 3수강평
- 김영한의 실전 자바 - 기본편
게시글
질문&답변
문제와 풀이 join() 활용2 - 코드 질문
안녕하세요. 생각하는자님t3.join()만 사용한다면, t1과 t2가 완료되기까지는 대기하지 않으므로, t1과 t2가 여전히 동작 중인데도 메인 스레드가 “모든 스레드 실행 완료”라는 메시지를 출력하게 될 수 있습니다.즉, 아래처럼 t1.join(), t2.join()를 빼고 t3.join()만 호출한다면:t1.start(); t2.start(); t3.start(); t3.join(); // t1, t2 는 join 호출 없음 System.out.println("모든 스레드 실행 완료"); 위 코드는 오직 t3 스레드가 끝날 때까지 기다리고, t1과 t2는 아직 동작 중일 수도 있습니다. 따라서 모든 스레드가 ‘정말로’ 끝난 시점을 보장하려면, 세 스레드 각각에 join()을 호출해야 합니다.결론적으로“모든 스레드가 끝난 뒤에야 다음 로직을 진행해야 한다”는 시나리오라면 t1.join(), t2.join(), t3.join()을 모두 호출하는 것이 맞습니다.“t3 스레드만 끝나면 되고, 나머지 스레드는 신경 쓰지 않아도 된다”는 상황이라면 t3.join()만 호출해도 문제가 없습니다. 하지만 실제로는 대개 “모든 스레드가 종료된 다음 작업을 진행해야” 하는 경우가 훨씬 많으므로, 주어진 예시에서는 세 스레드 모두 join()을 호출해야 의도대로 동작합니다.따라서 t1, t2, t3 모두 대기해야 합니다.MyTask에서 sleep() 시간을 모두 다르게 적용해보면 이해가 되실거에요.예를 들어서 t1이 100초간 실행되고, t2가 200초, t3가 1초간 실행된다고 가정해보겠습니다.t3.join()만 사용하게되면 main 스레드는 1초만 대기하고 넘어간 후에 "모든 스레드 실행 완료"를 출력하게 됩니다. 그 동안 t1, t2는 계속 실행되겠지요?감사합니다.
- 0
- 1
- 40
질문&답변
Setter메서드에 @Autowired
안녕하세요. hdh8990님스프링에서 의존성을 주입하는 방식(생성자 주입, 필드 주입, setter 주입 등)은 모두 결국 스프링 컨테이너가 관리하는 Bean에 대해서만 주입이 이뤄진다는 점에서는 동일합니다. 그래서 “어차피 구체 클래스(Concrete Class)를 스프링 빈으로 등록해야 한다면, 생성자 주입과 뭐가 다른가?” 하는 의문이 생기실 수 있는데요. setter 주입을 사용하는 대표적인 이유와 그 특징을 정리해보면 다음과 같습니다.1. 선택적 의존성(Optional Dependency)생성자 주입은 빈이 생성되는 시점에 필수로 주입이 이뤄져야 합니다. 만약 해당 의존성이 없다면 빈 생성 자체가 불가능하게 되고, 이는 곧 애플리케이션 구동에 문제를 일으키게 됩니다.setter 주입은 ‘필요하면’ 주입하도록 할 수 있습니다. 즉, 해당 의존성이 없더라도 빈 생성 자체가 가능하고, 상황에 따라 의존성을 주입하거나 주입하지 않을 수 있습니다.- 예) 어떤 기능에서 의존성이 반드시 필요한 것이 아니고, 특정 옵션에 따라 추가로 주입해야 할 수도 있는 경우 등. (@Autowired의 경우에도 빈이 없는 경우 무시하는 옵션들이 있습니다.)이처럼 “선택 혹은 변경 가능성이 있는 의존성”이라면, 꼭 객체 생성 시점에 의존성을 강제하지 않고 상황에 따라 주입을 결정할 수 있게끔 setter 주입을 고려해볼 수 있습니다.2. 런타임 중 변경(Setter 재호출)에 대한 유연성생성자 주입을 사용하면, 객체가 생성된 후에 해당 의존성을 변경하거나 교체하기 위해서는 빈 자체를 새로 생성해야 합니다.setter 주입을 사용하면, 이미 생성된 객체의 의존성을 필요에 따라 교체(재설정)할 수 있습니다. 스프링 컨테이너 입장에서는 잘 사용되지 않는 케이스지만, 순수 자바 코드 테스트나 특정한 환경에서 setXxx() 메서드를 직접 호출해 다른 구현체로 교체할 수 있다는 장점이 있습니다.물론 스프링 컨테이너에서 실제로 의존성을 재주입하는 로직을 자주 쓰는 일은 드뭅니다.3. 테스트 코드(순수 자바 환경)에서의 유연성생성자 주입의 경우, 테스트 코드에서 직접 객체를 만들어 테스트하려면 매번 해당 의존성들을 함께 생성해서 전달해야 합니다.setter 주입을 사용하면, 테스트 코드에서는 new SomeService()로 객체를 생성한 후, 필요한 의존성만 setXxx() 메서드를 통해 주입해줄 수 있습니다. 예를 들어 Mock 객체나 테스트 더블(Test double)을 쉽게 끼워 넣기 좋습니다.특히 스프링 컨테이너를 거치지 않고 순수 자바 코드로 단위테스트를 작성할 때, setter 주입은 객체 생성 → setter 호출로 매우 단순한 패턴으로 테스트를 꾸릴 수 있습니다.4. 결론 및 권장사항일반적으로는 생성자 주입을 권장합니다.- 왜냐하면 빈 생성 시점에 필요한 의존성이 충족되지 않으면, 컴파일 시점에 바로 오류를 찾을 수 있기 때문입니다.- 또한 불변(immutable)성을 확보할 수 있어 테스트와 유지보수에 유리합니다.setter 주입은 “선택적 의존성”이거나, 런타임 중 의존성 변경이 필요한 특별한 경우에 사용을 고려합니다.“선택, 변경 가능성”이라는 말은,스프링 관점에서는 필수 의존성이 아니다라는 의미(즉, 필요하다면 주입, 아니라면 생략)를 내포할 수 있고,테스트 관점에서는 순수 자바 코드에서 의존 객체를 쉽게 교체(주로 Mock) 할 수 있다는 것을 의미합니다.따라서 “setter 메서드에 @Autowired를 쓰든, 생성자 주입을 쓰든 결국 스프링 빈으로 등록해야 하는 거 아닌가?”라는 질문에 대한 답은 예, 그렇습니다입니다. 하지만 주입 시점과 옵션 처리 유무, 테스트 편의성, 런타임 동적 변경 같은 부차적인 관점에서 두 방식이 서로 다른 장단점을 갖게 됩니다.감사합니다.
- 0
- 1
- 24
질문&답변
채팅 프로그램 관련 질문이 있습니다.
안녕하세요. 사차님1. 세션별 스레드와 메시지 전송(전파) 스레드를 분리하면, 서로 책임을 분리할 수 있습니다. 프로젝트가 단순할 때는 최소한의 구현이 효과적이지만, 프로젝트의 규모가 커지면 책임을 분리하는 것이 더 나은 선택일 수 있습니다.2. 이 부분은 BlockingQueue로 해결할 수 있습니다. 자세한 내용은 관련해서 실전 자바 고급 1편 - 멀티스레드와 동시성 내용을 참고해주세요.감사합니다.
- 0
- 1
- 45
질문&답변
다대일 예시에 관한 질문입니다.
안녕하세요. hj.kang1409님이 관계라는 것은 한쪽만이 아니라 양쪽 모두의 관계를 생각해야 합니다. "다대일(many-to-one)" 관계를 이해할 때는, 양쪽 엔티티를 어떤 관점에서 보는지에 따라 다르게 인식될 수 있습니다. 예를 들어, Member(멤버)와 Team(팀) 의 경우를 살펴보면:팀 입장: 하나의 팀은 여러 멤버를 가질 수 있습니다. (1 : N 관계)멤버 입장: 하나의 멤버는 하나의 팀에만 속합니다. (N : 1 관계)이때 "다대일" 관계라고 하는 것은 "여러 멤버(Many)가 하나의 팀(One)에 종속된다"는 의미입니다. 즉, 멤버 테이블에서 team_id를 FK(Foreign Key)로 두고, 여러 멤버 레코드가 같은 team_id를 갖는 구조가 됩니다. "일대일" 관계가 아니라 "다대일"로 보는 근거는 '팀'이라는 엔티티가 하나 일 때 이를 참조하는 '멤버'가 여럿 존재할 수 있기 때문입니다.다대일 관계의 다른 예시사원(Employee) - 부서(Department)부서: 하나의 부서는 여러 명의 사원을 가질 수 있음 (1 부서 : N 사원)사원: 한 명의 사원은 딱 하나의 부서에만 속함 (N 사원 : 1 부서)→ 사원 기준에서 부서는 "다대일 관계"입니다.주문(Order) - 고객(Customer)고객: 한 명의 고객은 여러 개의 주문을 할 수 있음 (1 고객 : N 주문)주문: 하나의 주문은 단 하나의 고객에 의해 발생함 (N 주문 : 1 고객)→ 주문 기준에서 고객은 "다대일 관계"입니다.학생(Student) - 반(Classroom)반: 하나의 반(Classroom)은 여러 학생(Student)을 가질 수 있음 (1 반 : N 학생)학생: 한 명의 학생은 하나의 반에 속함 (N 학생 : 1 반)→ 학생 기준에서 반은 "다대일 관계"입니다.즉, "다대일 관계"라는 것은 한쪽 엔티티(멤버, 사원, 주문, 학생 등)에서 바라볼 때, 그 엔티티가 속하게 되는 다른 쪽 엔티티(팀, 부서, 고객, 반)는 단 한 개라는 점 때문에 붙는 명칭입니다. "다대일"은 "여러 개가 하나를 가리킨다"는 의미이며, 이는 "일대다" 관계와 동전의 양면처럼 동일한 관계를 다른 관점에서 해석한 결과일 뿐입니다.감사합니다.
- 0
- 2
- 19
질문&답변
자식 삭제 관련 문의 사항
안녕하세요. kshlove735님다음을 참고해주세요.https://www.inflearn.com/community/questions/56718참고로 실무에서는 잘 발생하지 않는 상황이기 때문에 너무 고민하지 않으셔도 괜찮습니다.감사합니다.
- 0
- 2
- 18
질문&답변
JpaMemberRepository를 만드는 이유?
안녕하세요. sh hyeogi365님JPA라는 기술이 스프링과 함께 사용되면서, 스프링 데이터 JPA 같은 기술로 더 추상화 됩니다.스프링 데이터 JPA 없이 JPA를 직접 다루는 경우도 있고, 또는 스프링 데이터 JPA로 더 편리하게 사용하는 경우도 있습니다.각각의 경우 장단점이 있는데요.JPA를 직접 다루게 되면 JPA가 제공하는 EntityManger를 직접 사용하면서 JPA가 제공하는 수 많은 기능을 사용할 수 있지만, 코드가 조금 늘어납니다. 스프링 데이터 JPA를 사용하게 되면 EntityManger 코드를 직접적으로 사용하지 않고 적은 코드로 기능을 구현할 수 있지만, 기능 구현에 한계가 있습니다.관련해서 더 자세한 내용은 실전 스프링 부트와 JPA 로드맵을 따라가보시면 더 자세히 배우실 수 있을거에요.감사합니다.
- 0
- 2
- 21
질문&답변
연관관계 강의 질문
안녕하세요. hj.kang1409님이 강의의 섹션6. 연관관계 매핑 기초 ~ 섹션7. 다양한 연관관계 매핑까지 학습하시면 됩니다.감사합니다.
- 0
- 2
- 11
질문&답변
interrupt() 메서드 사용 부분
안녕하세요. 혜진님이렇게 변경하면 이제 인터럽트는 Thread.sleep()을 호출하는 시점에서만 유효하게 처리됩니다. 즉, sleep() 중이 아닐 때 인터럽트가 들어오면 해당 인터럽트는 sleep() 호출 시 반영되지 않고, Thread.currentThread().interrupt() 플래그만 세팅된 상태로 다음 sleep()에서 예외가 발생합니다. 만약 sleep()와 같은 인터럽트 가능한 메서드 호출이 없는 코드를 실행하고 있다면, while(true)는 여전히 계속됩니다.감사합니다.
- 0
- 1
- 26
질문&답변
오타 제보
이희원님 감사합니다 🙂 다음 버전에 패치할게요^^!
- 0
- 2
- 22
질문&답변
404에러에 관한 질문 static 폴더밑의 jsp 파일조차 실행안됩니다.
안녕하세요. sh hyeogi365님도움을 드리고 싶지만 질문 내용만으로는 답변을 드리기 어렵습니다.실제 동작하는 전체 프로젝트를 ZIP파일로 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.그리고 build.gradle.kts(코틀린) 파일 대신에 강의와 같이 build.gradle 파일로 만들어서 진행해주세요.구글 드라이브 업로드 방법은 다음을 참고해주세요.https://bit.ly/3fX6ygx주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요추가로 다음 내용도 코멘트 부탁드립니다.1. 문제 영역을 실행할 수 있는 방법2. 문제가 어떻게 나타나는지에 대한 상세한 설명 (오류 화면, 오류 로그 포함) 링크: 공식 서포터즈링크: 자주하는 질문감사합니다.
- 0
- 3
- 44