마지막 스프링 프로젝트가 끝이나고 수요일날 수료를 했다. 마지막 프로젝트는 정말 험난했다. 팀원 한 명이 싸피에 붙어서 빠지게 되고 설상가상으로 나 또한 코로나에 걸리게 되었다. (이전 프로젝트 때 다른 팀원들이 걸렸었음... ) 근데 다행히도 이것저것 여건을 고려해서 프로젝트 부피를 너무 크게 잡진 않아서 프로젝트 기능 구현에는 문제가 없었는데 코로나 걸렸을 때 너무 힘든 시간을 보냈다. 구직활동은 자가격리로 인해서 전면 올스탑에 약먹고 자고 약먹고 자고 하는 상황이 되풀이 된다. 자가격리가 해제된 5일 후인 지금도 물론 코로나 후유증으로 기침을 달고 산다. 몸 건강한 것이 최고라는 게 새삼 느껴진다. 몸 안좋으면 코딩이 안된다. 뭔가 할 수 있다. 라는 생각보단 몸이 좋지 않으니 머리속에 떠올랐던 것이 실행으로 옮겨지지가 않는다.

 

 병원에 갔을 때 의사 선생님이 면역력이 약해져서 걸린것이라 그러셨다. 이번에 처음 걸린 코로나인데 그전까지는 운동을 꾸준히 해서 몸이 허약하다는 것을 느끼진 못했다. 그런데 하나의 프로젝트가 끝나고 일주일도 채 안되서 연달하서 하는 프로젝트가 원인이었다. 과거에 꾸준히 1만걸음씩 걷고 운동했던 내 몸의 패턴을 망쳐버렸다. 살도 많이 쪄버렸다. 인스턴스 음식을 많이 먹게 되고 학원 끝나고 오는 길에 뭔가 사먹어서 그런것 일수도 있다. 나같은 경우에는 몸관리를 꾸준히 해야하는데 무언가 외부의 압박이 있으면 그게 잘 되지가 않는다. 확실히 젊은 애들이 부럽기도 하다. 전날 과음을 아무리 많이 해도 멀쩡하게 학원 수업을 듣고 프로젝트에 참여한다. 

 

그래서 어제부터는 헬스장에 가기로해서 다니고 있다. 산출물 작업도 마무리하고 이제 포트폴리오 정리만 마무리해서 다시 구직활동 시작하면 된다. 어지럽던 나의 바탕화면은 이제 자주 사용할 소프트웨어 아이콘만 남기고 모두 정리하였다. 잠시 텅비었던 윈도우 캘린더에도 이제 내용을 추가하였다. 그리고 아침부터 공부를 하는 생활패턴을 깨고 싶지는 않아서 아침 8~9시에는 씻고 컴퓨터 앞에 앉아 있으려 한다. 아직 공부할 것이 많다. Docker 공부랑 학원 수업 복습을 해야할 것들이 많다. 코테도 조금씩은 준비하려고 하는데 잘 될지 모르겠다. 구직활동을 해보니까 요즘 왠만한 SI 회사들이 다 100대1이 경쟁률이 넘어가고 깐깐하게 신입을 뽑는 분위기였다. 그래서 그런지 더욱 오기가 생겨서 좋은 회사에 가고 싶다. 전에 봤던 회사 면접은 아쉽게 떨어졌다. 하지만 그 회사에 붙었어도 가지는 않았을 것이다. 붙는다면 7월초부터 출근이라고 했고 나는 그것에 대해 프로젝트 진행중이라 불가능하다는 것을 면접중에 말했던 것이 아무래도 크게 작용했던 것 같다. 이미 팀원 한명이 빠졌고 나 또한 빠져버리면 프로젝트가 터질것이 확실했는데 아마 이러한 것 때문에도 더욱더 회사 지원을 하지 못했다. 

 

이제는 다시 시작이다. 수료를 했으니 다시 일상으로 돌아가는데 내가 말하는 일상은 회사생활을 하면서 돈을 벌면서 사는 것이 일상이지 백수가 일상은 아니다. 끊임없이 계획을 잡아서 실천해야 한다. 학원에 친구들 보면 정말로 자기가 뭘해야할지 망각하고 방황하는 친구들이 많았다. 나또한 그랬긴 했는데 메모장부터 틀어서 이것저것 하나씩 뭔가를 적으니까 저절로 그걸 하게 되는걸 경험했고 목표의식과 강한 동기부여가 항상 필요하다는 것을 매번 느낀다. 

 

6개월 동안 좋은 선생님에게 수업을 들었다. 모든 질문에 성실히 대답해주셨고 기술적인 것도 최대한 많이 채워서 가르쳐주셨다. 스프링 부트, JPA, 스프링 시큐리티 등... 스프링 시큐리티는 따로 알려주시지 않을줄 알았는데 알려주셔서 프로젝트에 써먹을 수 있었다. 개인적인 질문이나 고민 같은 것들도 잘 들어주셨다. 처음엔 크게 기대를 하지 않았는데 결과적으로 좋은 선생님을 만나서 다행이었다. 늘 감사하다고는 생각을 하는데 그에 대한 확실한 대가는 내가 좋은 곳으로 취업하는게 아닐까 생각한다. 수료후에 방황하는 학생들을 보면 오히려 마음이 불편하실테니까... 앞으로가 진짜 중요한 시기인거 같다. 방황하지 말자..

 

 

'회고록' 카테고리의 다른 글

면접후기2  (0) 2023.07.29
강의부자  (0) 2023.07.24
면접후기  (0) 2023.06.24
포트폴리오 사이트 배포  (0) 2023.06.23
기술적인 고찰  (0) 2023.06.13

면접

 판교에 어느 IT 회사를 며칠전에 지원했었고 얼마 안 있어 면접날짜가 잡혔다. 지금같은 불경기에 신입을 많이 뽑고 따로 교육을 시킨다는 매력적인 조건이 있기에 더 끌렸고 우수한 자체 솔루션 기술이 있어서 그쪽 도메인 기술을 제대로 학습할 수 있는 기회가 많을거라 생각했다.

 

 면접은 화상면접으로 진행이 되었다. 면접관 2분과 면접자로 구성되는 2대 1면접이었다. 명시된 바로는 기술면접이라해서 적당한 자바나 스프링 지식이나 웹지식 등을 준비하였다. 근데 사실상 기술적인 디테일한것을 묻는 면접보단 인적성등을 확인하는 임원면접이었다. 나는 기술 면접이라길래 이것저것 질문 리스트해서 물어볼줄 알았는데 처음부터 1분 자기소개가 질문이었다. 당황은 했지만 그래도 대충 머리속에 있는 말을 내뱉었다. 근데 내가 말해도 이건 너무 구성이 별로였고 짧아서 면접관님들 표정이 좋지 않았다. "이게 끝?" 이라는 표정이었다. 나는 원래 포폴사이트를 미리 준비하였고 거기서 질문이 나오면 그 안에서 대답할 생각이었다. 솔직한 그대로의 내 모습을 보여주기 위해서 인위적인 준비를 따로 하지 않았는데 이렇게 개발자 면접이 평범한 느낌일거라는 생각을 못했다.(내가 유튜브에서 봤던 모의면접과 달랐다...) 물론 대기업 면접같이 비슷한 조건의 사람들 대상에서 조금만 절어도 떨어트리는 방식의 면접은 아닐거라 생각했다.

 

 다행히도 면접관님들이 나에 대해서 더 궁금하셨던지 아니면 기회를 더 줄려고 하셨던지 추가적인 질문을 즉각적으로 해주셨다. 전공은 본인과 잘 맞는지? 좋아하는 과목은 무엇인지? 왜 자바개발, 웹개발을 하려는지? 그리고 학원은 왜 가게 되었는지 등의 질문이다. 나는 여기서 나의 이력서에 곁들인 성장과정 내용을 반영해서 답변하였다. 다행이 내가 답변한 내용들은 내 포트폴리오 사이트에서 충분히 확인할 수 있는 자료와 수치들이 있어서 면접관님들을 충분히 납득시킬 수 있었다. 한치의 거짓없이 솔직하게 말하려고 노력했다. 학원을 다니면서 했던 프로젝트와 학원을 다니는 기간도 다 명시했고 지금도 수업을 듣다가 면접을 보는것이라 말했다. 다행히도 면접관님들도 학원출신 개발자들이 많다는 것도 알고 있었고 그분들이 대다수가 비전공자라는 것을 알고 계신다. 그분들이 전공자가 아닌데도 어떠한 방법으로 좋은 성과를 낼 수 있었는지도 알고 계셨다. 이 부분에서 공감대를 찾고 프로젝트 경험과 느낀점에 대해서 나의 의견을 말하는데 대부분의 시간을 보냈다. 그래서 그런지 후반부로 갈수록 분위기는 좋았다. 정말로 인품이 좋으신분들이라 다행이었다. 면접자의 약점을 찾아서 깍아내리기보단 다른 방향으로 나의 스토리라인을 이끌어주셨다. 특히 프로젝트 경험을 말하는 과정이 제일 중요했는데 여기서 나의 빈틈은 정말많이 발견되었다. 이부분을 좀 더 보완하고록 노력해야겠고 스프링에 대해서 면접관님들은 나에게 디테일하게 묻지는 않았으나 본인이 스프링 숙련도가 얼마냐 되냐는 질문을 하였을 때 나는 제대로 답할 수가 없었다. 그냥 배우는 과정이라 답했다. 그 상황에서 스프링 용어와 함께 프로젝트 경험을 같이 예시 들어서 대답했어야 했는데 그렇게 하지 못한 내가 확실히 아직 기술력이 조금 부족하다고 느꼈다. 지금도 스프링 공부를 해야하는데 왜 글을 쓰고 있는지도 의문이다. 취업시즌이라 붕뜬 느낌인데 이런 느낌 정말 혼란스럽다. 프로젝트를 해야하는데 학원을 못간 상황도 조금 괴롭다. 학원에 면접 볼 자리가 있었으면 좋았을텐데... 그 시간에 교육생 선발 면접 때문에 빈 방 하나를 못두는 상황이었다. 다음주부터는 이런 혼란스러운 감정을 정리하고 프로젝트에 매진할 생각이다. 좋은 경험치 하나가 쌓였으니 그 대가를 치뤘다고 생각하고 있다. 

 

배운점

 면접이 끝나고나서 그때 나에게 왜 기회를 더 줄려고 했는지 곰곰히 생각해보았다. 만약에 내가 비전공자였고 아무런 자격증이 없고 포트폴리오 사이트를 보여주는 등의 준비를 안했다면 그냥 그대로 면접을 끝났을 것이다. 또한 한편으로는 어느정도의 스토리 라인을 정리했어야 하는 생각도 많이 했다. 면접은 20분 동안 온전히 나에 대한 이야기를 하는 자리다. 그 자리에서 내가 내 이야기를 짧게 말하거나 재미없게 말하면 면접관님들도 나에게 관심을 가질 이유도, 나를 뽑을 이유도 줄어드는 것이다. 이러한 면접은 나에게 엄청나게 큰 공부가 되었다. 단지 수업만 듣는게 공부는 아니다. 주변 같은과 학우들이 실력이 있더라도 이런 번거롭고 어려운 면접의 벽을 못넘고 중소기업으로 빠지는 경우도 있다. 나를 잘 설명하고 납득시키고 왜 여기서 일을 하면 좋은지, 왜 뽑고 싶은 인재인지 설명하는 것은 무척 어려운 일이지만 그것을 해야 높은 곳으로 갈 수 있다. 이것은 업무와도 연관되어 있다. 자신의 생각을 잘 표현해야 커뮤니케이션이 된다. 이러한 생각을 할 수 있게 도움을 준 면접관님에게 감사하다.

 

 그리고 여러명의 지원자들 대상에서 하는 면접도 준비를 해야겠다고 느꼈다.어제 면접은 개인 면접이라 그런 분위기였지만 2명 이상의 면접에선 나와 타인을 비교하게 되고 나에 대한 부정적인 판단을 할 수 있게 되는 것을 조심해야 겠다고 느꼈다. 나는 공모전이나 해외 연수 경험 같은게 없고 나이가 많다는 점이 약점으로 작용할 수 있다. 그리고 CS지식을 깊게 준비하지 못했고 알고리즘 공부도 많이 해놓지 못했다. 그러면 2인 면접을 하게 되는 경우 나와 정반대의 지원자를 붙여놓을 가능성이 있다. 이부분을 조심해야겠다는 생각이 들었다. 아직 봐야할 면접들이 많은데 다음엔 더 성장해야겠다는 명분과 방향성이 생겼으니 좀 더 분발하려고 한다. 

 

 

'회고록' 카테고리의 다른 글

강의부자  (0) 2023.07.24
마무리  (0) 2023.07.14
포트폴리오 사이트 배포  (0) 2023.06.23
기술적인 고찰  (0) 2023.06.13
최근 고찰  (0) 2023.05.03

 포트폴리오 사이트를 배포하였다. 처음에 github.io로 배포하려고 했지만 github.io는 public 저장소만 배포가 가능했다. 그렇다고 해서 aws로 톰켓으로 배포하기에는 ip주소를 적절한 도메인 이름으로 변환하는 과정이 번거롭기도 하다. 내가 작업하던 github 저장소는 private 저장소인데 개인 포트폴리오에 대한 정보도 어떻게 보면 인적사항이라 쉽게 공개하기가 꺼려진다는 문제가 있었다. 그래서 고민하던중에 netlify라는 걸 써보기로 했다. 선생님 제자분 포폴이 netlify로 배포하였었는데 그게 얼핏 떠오른 것이다. netlify는 정적 웹페이지를 위한 배포 기능을 제공한다. 이것으로 나의 목적인 git private 저장소 배포도 가능했다.

내 포트폴리오 사이트는 처음부터 반응형을 목적으로 디자인하였다. 핸드폰으로 보는데 화면이 깨지지 말아야 한다는 제약사항이 존재하는 것이다. 이를 위해 부트스트랩을 사용하였고 메뉴버튼을 누르면 드롭다운으로 펼쳐진다. 내용물은 화면을 좁히면 그에 맞게 너비가 줄어들어야하고 두개의 카드를 기본으로 배치하다가도 디바이스별 그리드 속성을 주어 특정 크기가 되면 한 로우에 한개씩 배치가 된다. 화면이 너무 작으면 글자 배치가 이상하게 보이기도 했는데 그것을 확인후에 코드를 수정하고 git에 다시 push해서 올렸더니 바로 배포가 자동으로 되었다. 정말 편리했다. 큰 프로젝트를 반응형으로 한번쯤은 해보고 싶긴하지만 이게 정말 힘든 작업이다. 정적인 웹 페이지니까 이렇게 글자 개수도 강제로 맞추지만 글자 개수가 동적으로 다양한 경우가 생기는 경우에는 아예 반응형으로 설계하는 것보다 모바일 전용 페이지를 따로 만드는 방법을 쓰기도 한다. URL로 뒤쪽에 netlify.app라는 것이 붙지만 앞에 도메인 이름부분은 자유롭게 지정이 가능하다. 이것도 정말 편했다.

 

사실은 이게 잡코리아 이력서에 같이 첨부하려고 만든 것이지만 요즘 이상한 솔루션 회사에서 자꾸 이력서를 열람하고 포지션 제안을 오는 경우가 있어서 결국은 포폴 사이트는 비공개로 하기로 했다. 나중에 기회되면 동료에게 보여줘야 겠다.

'회고록' 카테고리의 다른 글

마무리  (0) 2023.07.14
면접후기  (0) 2023.06.24
기술적인 고찰  (0) 2023.06.13
최근 고찰  (0) 2023.05.03
Git을 쓰면서 파일을 다 날릴 뻔 한 경우  (0) 2023.04.13

AWS에 설치한 Oracle

이번 프로젝트에서 다양한 라이브러리와 툴을 사용해보았다. 이전부터 구상하던 것이었지만 팀원 모두가 접근할 수 있도록  AWS에 오라클 데이터베이스를 설치하여 사용하였다. 사실 RDS를 사용하고 싶었지만 기존에 사용하던 오라클 버전을 지원하지 않는다는 문제로 인해서 어쩔 수 없이 AWS에 오라클을 설치하였다.

 

AWS의 OS는 우분투 20.04를 사용하였다. 윈도우를 사용하면 편했겠지만 공부를 위해선 우분투를 택하는게 낫다고 판단하였다. 이전에 메타코딩 aws 강의를 들었던 기억으로 서버 구축이랑 고정 IP 할당하는 것은 쉽게 할 수 있었다. 리눅스 명령어로 오라클 설치하고 포트 포워딩 하는데 온갖 고민거리가 많았지만 반나절 고민하고 구글링하니까 자연스럽게 해결되었다.

 

aws 우분투는 처음에 movaexterm으로 접속하면 ubuntu라는 계정으로 접속해야 한다. 나는 무언가의 권한 에러를 우려해서 처음부터 root 계정을 뚫었다. root 계정 뚫는것도 기본적으로 막혀 있었지만 어찌어찌해서 뚫는데 성공하였다. 그렇게 무사히 오라클 설치를 완료하고 sql developer까지 접속하였다. 고정아이피를 뚫기 전에 인스턴스를 중지시키니까 당연히 IP가 바뀌는 것을 확인하고 고정아이피를 뚫었다. 근데 오라클이 접속이 되지 않아서 이것도 몇시간 고민했는데 그냥 스쳐지나간 검색이 해답을 주었다.

 

"oracle 계정으로 접속하라"는게 답인데 이게 뭔가 고민하는데 알고보니 리눅스 oracle 계정이 따로 있었다는 것이다. 뭔가 다른 방화벽 문제인줄 알았는데 그게 아니니 안도의 한숨을 쉬었다. 누군가 여기선 방화벽 때문에 접속이 안될거란 말이 있어서 더 그랬을 것이다. 

 

AWS 오라클은 뚫어논 것은 사실 프로젝트 시작초였으나 사용한 것은 프로젝트 끝나기 5일전이다. 미리 사용하기엔 DB 테이블 정의 작업이 완전치 못했고 기능정의가 모호하였다. "여기서 바로 테이블 생성하고 쓰기엔 온갖 수정사항이 생길 것이다." 라고 생각했다. 최대한 미루고 미뤘는데 그래도 계속 테이블 수정이 발생되던건 어쩔수 없나보다..

 

AWS DB 덕분에 학원 PC를 따로 파서 굳이 작업을 하지 않아도 되었다. 근데 이게 혼자 작업할 때는 정말 편한거같다. 문제는 여러명이서 동시에 접속해서 작업할 때이다. AWS 인스턴스 가용 메모리가 1GB여서 동시에 많은 쿼리가 오면 뻗어버린다. 내가 하필 그 때 이용자 정보 기능 테스트하느라 480개의 레코드를 새로고침을 하였고 동시에 다른 팀원들도 테스트를 하였나본데 어느 순간 DB가 멈춰버렸다. 처음엔 당황했는데 30분 넘게도 안돌아와서 그냥 인스턴스 중지시키고 다시 틀었다. 근데 똑같이 DB 접속이 안되서 oracle 계정으로 뚫었다. 이렇게 문제는 항상 반복되나 싶었다... 여기서 배운 교훈은 AWS에 설치한 오라클로 팀작업시 테스트는 따로따로.... 하자....는 것...

 

Figma

UI 화면 디자인을 피그마로 하였다. 왜 피그마로 했냐면 원래 파워 포인트로 하다가 갑자기 다른팀에서 피그잼으로 하였다길래 우리도 피그잼으로 하려다가 피그잼은 html 추출이 안된다는 말듣고 피그마로 바꿨다. 피그마는 여러명이서 동시에 접속하여 협업이 가능하고 teleportHQ라는 플러그인으로 디자인한 레이아웃을 html로 추출이 가능하다. 문제 문제는 타히트한 레아이웃이 잡혀야하고 클래스명을 ui 디자인시에 직접 지정해줘야 했다는 것이다. 사실상 초보자는 능숙하기 쓰기 불편하였다. 어떤 친구는 그걸 뽑아서 쓰기도 했는데 html 클래스명이 진짜 보기가 이상할 정도였다. 그리고 구조도 원래 디자인한거와 다른게 많았다. 이렇게까지 써야 하나 싶어서 다시 부트스트랩으로 돌아와서 디자인하였다. 근데 피그마로 디자인 한거라도 있으니 부트스트랩으로 클론코딩하는거마냥 뽑으니 어느정도 디자인의 혈은 뚤렸었다. 디자인이 늘 고민이다. 항상.. 그래도 피그마에 발한번 담근거 다음 프로젝트 모바일 화면 디자인할 때는 써봐야겠다.

 

Erdcloud

2차 때 DB 작업 하는게 매우 답답하였다. 나는 2차 때도 모두가 DB 설계를 해보길 바랬다. 근데 그렇게 되진 못했던거 같다. 그래서 이번엔 모두가 작업하는 상황을 구상했다. erdCloud라는게 있는데 한번 써보자고 했다. 대충 한번 써보고 사용법 알려줘보고 같이 써봤는데 대강 틀 그리는데 4~6시간 걸렸나 싶다. DDL 추출도 되니 바로 이제 DB 끝? 이랬는데 FK제약조건은 왜 안걸려있고 왜 테이블명이랑 컬럼명은 " "들어가서 생성되있는건가...? 그래서 결국 뒷작업하느라 애좀 많이 먹었다는 것... 그래도 이 툴은 정말 좋고 편했다. 화면도 공용이서 쓰기 좋았고 DB 작업 같이한다는게 낭만 아닌가? 그리고 변경사항 바로바로 반영해서 ddl 고치고 하는건 많이 편했다. 

 

Github

나는 git에 대해 완벽하게 안다고 말하지 못한다. 생활코딩 강의랑 메타코딩 git 강의를 보고 배우긴 했는데 실제로 프로젝트에 제대로 적용은 하지 못했다. 이번 프로젝트 때 처음 적용했는데 나도 팀원들에게 알려주면서 많이 배웠다. HEAD가 attach 되는 상황에서의 해결법 등... 작업을 정해진 기준에 따라서 작업만 한다면 문제는 일어나지 않는다. 근데 예를 들면 develop에서 머지 후에 자기 브렌치로 돌아가지 않고 develop에서 작업하고 커밋한다든지 이러면 문제인거다. 아니면 실수로 HEAD 위치를 바꿔버린다던가 한 사람이 삭제한 것도 커밋해버리면 문제인거다. git은 여러 사람중 누가 팀장인지 모른다. 추적된 파일에 대한 삭제 또한 기록한다는 것. 그리고 merge를 너무너무너무 늦게한 사람이라면 그사람 gitignore에 내용 추가가 안되어서 늦게 merge 되버리면 또 갑자기 파일이 추적되는 경우도 있다. 그리고 프로젝트 중간에 어떤 친구가 작업한 파일이 다 날라갔다고 말하는 상황이 있었으나 알고보니 따로 클론한 저장소랑 현재 작업하고 있던 저장소랑 헷갈려서 파일이 날라간줄 알았던것이다... 그래도 그걸 찾았다는게 다행이었다. 못찾았으면 멘탈이... 완전 ...

여러 상황 다 보았지만 그래도 commit과 자기 브랜치에 push는 미리미리 해놓고 로컬에 브랜치를 날려버려 해결하면 아무 문제없다.

추가로 했으면 하는 것 

AWS 배포, 파일 서버필요

사실은 AWS를 처음 인스턴스를 받았을 때부터 웹프로젝트를 배포해야 겠다는 생각은 있었으나... 프로젝트 특성상 이미지 업로드와 로드가 빈번한 상황이 올거를 예상하고 배포까진 못했다. 그리고 파일서버가 하나 필요하다고 생각했다. 파일 업로드 구현시 파일은 빌드된 폴더 안쪽으로 저장된다. 이것을 하나의 파일서버로 올려두면 팀작업시 수월할 것이다. 근데 이게 안되니 파일공유가 안되는 아쉬움이 있었다. 

추가적인 라이브러리 사용

이번 프로젝트에서 못쓴 라이브러리가 몇개 있다. 결제 API나 sumernote는 좀 쓰고 싶었다. 근데 내가 한번 구현하고 프로젝트에 넣어보고 싶었으나 사실 그럴시간이 없었다. 그래도 메일 api나 캘린더 api는 한번 써봤다. 그리고 부트스트랩 템플릿에 딸려있는 테이블 api는 매우 좋았다. 페이징 구현이 따로 필요없는 테이블... 하지만 이거 때문에 오라클 DB가 뻗어버림 하.. 못쓴 라이브러리나 좀더 알아야할 라이브러리는 다음 프로젝트를 기약하자.

'회고록' 카테고리의 다른 글

면접후기  (0) 2023.06.24
포트폴리오 사이트 배포  (0) 2023.06.23
최근 고찰  (0) 2023.05.03
Git을 쓰면서 파일을 다 날릴 뻔 한 경우  (0) 2023.04.13
SQLD 합격 후기  (0) 2023.04.07

최근에 스프링으로 프로젝트를 시작 했는데 자꾸 애너테이션을 쓰려고 하니까 그 사용처와 왜 써야할지가 생각이 나질 않는다... 그래서 공부목적으로 내가 배웠던 그리고 알고 있는 애너테이션의 의미와 기능을 짤막하게  정리하려 한다. 

 

  • @Controller : 프로그램이 원격호출 가능하도록 등록하는 애너테이션
  • @RequestMapping : URL과 클래스, 메서드를 연결
    •  @RequestMapping은 클래스 위에다가도 쓸 쑤 있고 메서드 위에다가도 쓸 수 있다. 
      • 클래스 위에다가 쓰면 url 상위 Path를 지정한다. 
    • @RequestMapping(method = RequestMethod.POST, path = "/postMethod")
    • @RequestMapping(method= {RequestMethod.POST, RequestMethod.GET})
      • post,get 둘다 넣을 수 있다.
  • @GetMapping : get 요청 정의
  • @PostMapping : post 요청 정의
  • @PutMapping : 수정
  • @PatchMapping : 수정
    • put, patch의 차이가 뭘까...? 
  • @DeleteMapping : 삭제
  • @RestController : rest api 구현시 클래스 위에 붙인다. 
    • @RequestMapping + @ResponseBody 두개 합친거와 같다. 
  • @RequestBody : 요청 파라미터가 Json으로 컨트롤러로 오는 경우 유저가 정의한 자바객체로 바인딩해준다.
  • @ResponseBody  : @RestController를 사용하면 자동으로 @ResponseBody를 붙여준다. 컨트롤러에서 반환하는 객체를 json format 으로 바꿔준다.
  • @PathVariable : Restful API 작성시 URL에 중간에 번호 같은걸 넣을 때 URL path에 있는 값을 가져온다. 
  • @RequestParam : 요청할 때 넘어온 파라미터를 매개변수에 연결할 때 쓴다.
    • 데이터를 GET, POST 둘다 받을 수 있다.
    • 요청으로 넘어오는 파라미터을 String, int, boolean, Integer등 원하는 단순한 타입으로 매핑이 가능하다. 
    • 쿼리스트링으로 url에 key, value를 붙이는데  그것을 컨트롤러 단에서 받아서 처리해야 하는 경우를 위한 애너테이션인데 기존 서블릿에서는 Httpservletrequest 객체로 getAttribute로 이것을 처리했었다.
    • 옵션을 넣어줄 수가 있으며 다음과 같은 옵션이 있다.
      • name, required, defaultValue
        • name : key 이름을 지정
        • required : 파라미터를 필수로 입력할 것인가에 대한 여부를 결정
          • true면 필수로 입력해야 한다는 것
            • 이것을 true라고 지정했다는 것으로 인해 발생될 에러의 경우를 고려
          • false는 필수로 입력하지 않아도 좋다. 
            • 이런경우엔 defaultValue를 지정하거나 예외처리 로직을 고려해야 한다.
        • defaultValue : 기본값이다.
  • @ModelAttribute : 적용 대상을 Model의 속성으로 자동으로 추가해주는 애너테이션이다. 
    •  적용 대상이 되는 객체는 setter가 정의되어 있어야 한다. 
    • 기존에 view 페이지로 보내줄 데이터를 Model에 담아서 m.addAttribute("key", value); 와 같은 방식을 사용하였다. (Model m이라 선언함)
    • 그런데 m.addAttribute와 같은 코드를 쓰지 않더라도 @ModelAttribute Myclass mycls 요런식으로 매개변수로 넣어준다면 key, value가 자동으로 지정되어서 m.addAttribute와 같은 동작이 처리된다.
    • key는 default로 클래스 첫번째 문자를 소문자로 바꿔서 적용 MyClass ---> myClass
    • 키값을 직접 지정 가능 
      • @ModelAttribute("myModel") Myclass mycls : 이렇게 지정해주면 key값이 myModel로 된다.
    • 파라미터를 검증할 수 있는 기능을 제공한다. BindingResult를 같이 붙여서 쓸 수 있음
    • Spring MVC에서 @ModelAttribute는 값을 객체로 바인딩할 때 프로퍼티 접근법을 사용한다.
      • 해당 객체를 생성(기본생성자)
      • 프로퍼티 접근법인 setter를 사용하여 넘어온 값을 객체에 주입
      • 하지만 모든 필드를 매개변수로 받는 생성자를 만들어도 setter가 없더라도 정상적으로 바인딩은 된다.
  • WebDataBinder가 타입변환, 데이터 검증 작업을 해준다.
  • ★ @ModelAttribute 나 @RequestParam이 생략되었더라도 파라미터의 Type이 뭐냐에 따라서 자동으로 붙여준다. 
    • Type이 참조형일 때 > @ModelAttribute
    • Type이 기본형, String 일 때 @RequestParam
  • @RequestParam으로 여러개를 받다가 너무 많아지면 객체를 정의해서 @ModelAttribute로 관리한다.
  • @ WebServlet은 서블릿에서 쓰는 애너테이션인데 스프링의  @Controller와 @RequestMapping을 합친 개념이다.
  • @ExceptionHandler : 예외 처리를 위하 쓰는 애너테이션이다. 
    • 메서드 위에 @ExceptionHandler(예외클래스.class) 붙이고 에러 페이지 리턴하여 사용
  • @ControllerAdvice : 컨트롤러 전역에서 발생하는 예외를 처리할 때 @ExceptionHandler와 같이 쓴다.
  • @ResponseStatus : 응답 메세지의 상태코드를 변경할 때 사용할 수 있다. 
    • @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) : 405 상태코드로 변경(METHOD_NOT_ALLOWED)
  • @CookieValue(value="id", required=false) Cookie cookie: 쿠키 중에서 id키로 해당 쿠키를 찾고 맞는 정보를 Cookie 객체에 저장해준다. cookie.getValue()로 값 확인 
  • @Data : lombok에서 제공해주는 애너테이션인데 @Getter , @Setter , @ToString , @EqualsAndHashCode , @RequiredArgsConstructor를 자동으로 적용해준다.
  • @AllArgsConstructor : 모든 필드를 넣는 생성자를 만들어줌 
  • @NoArgsConstructor : 기본 생성자를 만들어줌 
  • @InitBinder : 변환 과정에서 바인딩 처리를 위한 애너테이션이다. 해당 컨트롤러 내에서만 가능
  • @DataTimeFormat(pattern="yyyy/MM/dd") : 시간 객체를 원하는 형태로 바인딩 가능하다.
  • @NumberFormat : format 지정을 위한 애너테이션이다. 숫자 관련 형식 지정이 가능 
  • @Valid : 검증을 위한 애너테이션인데 이것도 커스텀으로 Validator 클래스를 따로 만들고 @Valid 애너테이션을 붙이면 해당 객체가 컨트롤러로 들어오면 검증을 하고 그 결과를 BindingResult 객체에 담아준다. 
    • 자바 애너테이션이고 Bean Validation API 검색해서 maven에서 가져다 쓰자. 
  • @Component : 개발자가 작성한 클래스를 Bean으로 만들겠다라는 의미다. 이것을 사용하면 Bean Configuration 파일에 Bean을 등록하지 않아도 사용이 가능하다. 
    • <context:component-scan base-package="패키지경로" /> 이걸 xml파일에 지정해주면 해당 패키지 경로안에 있는 @Component붙은 클래스를 찾아서 검색한다.
    • @Controller, @Service, @Repository, @ControllerAdvice는 @Component가 내부적으로 들어가 있다.
  • @Configuration  :스프링 IOC Container에게 해당 클래스를 Bean 구성 Class임을 알려준다.
  • @Bean : 개발자가 컨트롤이 불가능한 외부 라이브러리들을 Bean으로 등록하고 싶은 경우에 붙인다. 
    • @Configuration과 같이 쓰는데 @Configuration을 클래스 위에, 메소드 위에다가 @Bean을 쓴다. 
  • @Autowired : Bean을 자동으로 주입해준다. 
    • Controller에 dao객체나 service 객체를 @Autowired로 주입하는 경우가 많음
    • xml에 component-scan을 해놓자 쓰기
    • 주의할 점은 type으로 해당 bean을 검색한다. 검색시에 중복되는 type이 있으면 에러를 띄워준다. 
      • 그걸 경우 @Qualifier 애너테이션을 붙여서 내가 어떤 클래스를 빈으로 주입하는지 명시해야 한다.
  • @Resource : 마찬가지로 Bean을 주입하는 애너테이션인데 @Autowired와 차이점이 있다면 이건 byName으로만 검색한다. 
  • @Inject : Autowired와 비슷하고 @Named를 추가적으로 사용해서 이름기준으로 주입할 Bean 지정하능, @Qualifier도 사용가능
    • javax 라이브러리 필요
    • Bean을 검색하는 기준의 순서가 조금 다름
      • Autowired : 타입 > 이름 > @Qualifier
      • Inject : 타입 > @Qualifier > 이름
  • @Value : 기본형 타입의 값을 주입할 때 써준다.
  • @Transactional  :  트랜잭션과 관련된 애너테이션 > 트랜잭션 처리 적용
    • 어노테이션 기반 AOP를 통해 구현
    • 트랜잭션 setup, commit, rollback, close 코드를 알아서 넣어준다.
    • rollbackFor 붙여주기
    • <tx:annotation-driven/> 필요
  • Test시에 @RunWith으로 Junit 명시, @ContextConfiguration로 xml 파일 위치 명시
  • 계층에 따른 코드를 다음의 애너테이션으로 구분
    • @Controller : 표현 레이어 (표현계층, 컨트롤러)
    • @Service : 서비스레이어(business 계층)
    • @Repository : 영속계층(persistant 계층)
  • @PostConstruct : 이 애너테이션을 메서드 위에 달면 bean 생성 후에 메서드가 실행
  • @PreDestory : Spring이 application context에서 bean을 제거하기 직전에 단 한번 실행
    • @PostConstruct , @PreDestory 둘다 javax-annotation-api 라이브러리꺼

'스프링(부트아님ㅋ)' 카테고리의 다른 글

DispatcherServlet 정리  (0) 2023.07.16
스프링 IoC + DI  (0) 2023.05.05
스프링 MVC 5.0.7에서 모바일 화면 적용하기  (0) 2023.05.02

 학원 수업 복습을 어떻게 해야할 지 늘 고민해왔다. 첫번째로 한 방식은 학원에서 배운 코드를 github에다가 올리고  지하철에서 모바일로 열어서 보면서 복습하고 PC로는 github repository 내 단어 검색으로 원하는 키워드를 찾아서 기억이 안나는 부분을 상기시켰다. 그런데 어느날 코드 키워드 검색기능이 되질 않는다. 몇주 전까지만해도 잘만쓰던 기능이 왜 안될까? 

 

그런데 위의 방법은 단점이 많았다. 의외로 복습 빈도가 그렇게 많지 않았고 빠르게 훑어보기에는 후반에 갈수록 너무 많은 파일들이 있었고 텍스트로는 담을 수 없는 시각적인 내용도 있고 또한 키워드 검색기능도 안되니 진짜 이제는 쓰기 더어려워졌다. 기억의 리프래쉬는 약 한달이라는 마지노선을 가지고 있다. 그 한달이 지나버리면 과거에 들은 수업 내용을 다시 머리속으로 재생시키는데는 +@의 노력이 더 붙는다. 지금까진 프로젝트 시작전 주말마다 복습을 해왔다. 사실 전공자임에도 학원에서 처음 배우는 내용이 많았다. front쪽은 기초적인 것들만 배웠고 spring 책들은 다들 독자가 이미 알고 있는것을 전제로 했으니 기초지식을 배울 기회도 전혀없었고 그 누구도 그 필요성을 강조하지 않았다. 이렇게까지 기초적인것부터시작해서 상위 지식으로 올라가는게 지금이 아니면 절대 오지 않을 것 같다. 이건 매우 감사한 기회라고 생각한다. 

 

 그래서 결국 생각해낸 방법은 README.md 파일 한 페이지에 배운 내용을 정리하는 것이다. 여기에는 복습하면서 추가적인 공부를 하면서 내용을 채우고 공부과정에서 내가 생각한 내용, 그리고 시각적으로 설명해준 내용을 덧붙일 수 있다. 구현 아이디어를 장황한 코드가 아니더라도 몇 줄의 정리된 문장으로 적어놓으면 다시 상기시키기 쉬울거라 생각했다. 그리고 한페이지로 작성하는 것은 keyword 서치를 위한 방안인데 이것도 내용이 많이지면 보기가 힘들어지는게 많아질것이다.. 그리고 반드시 수업 끝난 후 일주일 이내에 작성하도록 하자. 어려운 문제를 해결할 수 있는 원동력은 첫번째는 끈기이고 두번째는 기본기이다. 끈기(?)는 아직 잘 모르겠고 기본기라도 잘 쌓아놓자.

 

https://github.com/ngotic/ServerBasic

 

GitHub - ngotic/ServerBasic: 서버개념정리

서버개념정리. Contribute to ngotic/ServerBasic development by creating an account on GitHub.

github.com

 

 

'잡담' 카테고리의 다른 글

블로그 정리 예정  (0) 2023.07.16
Notion이라는 것을 공부했다.  (0) 2023.02.20
곧 IT 지식을 포스팅 할 예정  (0) 2023.02.18

자바 8에서 추가된 스트림 개념은 배열이나 컬렉션을 다루는 개념으로 다양한 프레임 워크를 다루는데 혹은 클린코드 등의 주제에서 많이 등장한다. 자바8이라고 해서 얼마 안된 느낌이지만 이러한 기술이 뭔가 지금 사용하는 기술에 매우 유용하게 사용되고 있는 것 같아서 정리하려고 한다. 

 

스트림에서 주로 사용되는 것은 람다식과 표준 API 함수 인터페이스다. 뭔가 낯선 개념이지만 하나씩 정리하려 한다.

 

람다식

함수형 프로그래밍 방식을 지원하는 표현식이다. 컬랙션 or 배열 조작을 위한 방법으로 사용되며 이러한 람다식을 사용하면 코드가 매우 간결해진다. 먼저 람다식을 표현하는 방법에 대해 살펴보자

 

람다식 작성 법칙

람다식은 익명 함수다. 이름이 없는 함수다. 람다식은 아래와 같이 작성된다. 

// 일반 함수(메서드)
int max(int a, int b) {
	return a > b ? a: b;
}

// 람다식으로 바꾼 식
(a, b) -> a > b ? a: b;

함수의 return 타입과 함수 이름이 사라지며 ()와 { } 사이에 화살표(->) 가 추가 된다.  또한 정해진 규칙에 따라 특정 형태에서 타입, 괄호, return, 세미클론 등을 생략할 수 있다. 

 

1. 매개변수의 타입이 추론 가능하면 생략가능하다.(보통 제네릭과 함께 사용되어 타입이 추론된다.)

(int a, int b) -> a > ? a: b  ☞ (a, b) -> a > ? a: b

2. 괄호({   })안에 문장이 하나인 경우 괄호({  })가 생략하능하다. 괄호가 생략되는 경우 끝에 세미클론(;)을 붙이지 않는다.

(int a, int b) -> { return a > b ? a : b; }  ☞ (int a, int b) -> a > b ? a : b
  • 주의 사항
    • 매개변수가 하나일 때만 (  )를 생략할 수 있다. 두 개이상일 때는 (  )를 생략 불가 / 그리고 (  ) 를 생략하는 경우에는 자료형도 함께 생략한다. 매개변수 옆에 자료형이 붙어 있다면 (  )는 생략할 수 없다. 
    • return이 붙어있다면 {   } 를 생략할 수 없다. 
  • 람다식 접근 순서
    • 먼저 함수 이름, 반환타입 제거하고 ( )과 { } 사이에 -> 를 넣자
    • 매개변수가 2개 이상이면 ( )를 지우지 말고 제네릭으로 매개변수 타입이 추론 가능하면 매개변수 타입을 지우고 {  } 안에 문장이 1개이면 return을 지우고 return을 지우면 {  } 를 지우고 {  } 안에 있는 세미클론(;)을 을 빼자

 

람다식은 사실 익명함수가 아니라 익명객체이다. 

(a, b) -> a > b ? a : b   

↕ 위 아래는 사실 동일한 표현

new Object() {
	int max(int a, int b){
    	return a > b ? a : b;
    }
}

Object obj = new Object() {
	int max(int a, int b){
    	return a > b ? a : b;
    }
}
Object obj = (a, b) -> a > b ? a : b ;// 에러
int value = obj.max(3, 5); // 에러

사실 람다식은 Object로 정의한 익명클래스다. 그래서 익명 객체라고도 한다. 하지만  obj.max(3, 5);을 호출하려고 하기에는 Object에서 max가 정의되지 않아 에러가 난다. 결과적으로 반드시 함수형 인터페이스를 써야 한다. 

 

함수형 인터페이스 

단 하나의 추상 메서드만 선언된 인터페이스다. @FunctionalInterface라는 애너테이션을 붙이는데 이 직접 함수형 인터페이스를 구현할 때 @FunctionalInterface를 안붙여도 에러는 나지는 않는다. ( @FunctionalInterface를 붙이면  인터페이스에 메서드를 2개이상 정의시 컴파일 에러를 띄운다. ) 그리고 이것은 익명 클래스와 비슷하다. (interface냐 class냐 차이)

 

interface MyInterface {
	public abstract int max(int a, int b); // 추상메서드는 이거하나 만듬
}

위의 인터페이스의 메서드는 아래의 코드에서 익명 클래스로 메서드가 구현이 되고 인터페이스 자료형으로 메서드를 호출한다. 

MyInterface m = new MyInterface() { // 
    @Override
    public int max(int a, int b) {
        return a > b ? a : b;
    }
};

int value = m.max(3, 5);  // 위의 호출을 다음의 방식으로 해결, 왜냐면 MyInterface에 max 메서드가 정의되어 있다.

↕ 위, 아래 동일

MyInterface f = (a, b) -> a > b ? a : b; 
int value = f.max(3, 5);

// 축약시에는 new MyInterface() { } 부분이 벗겨진다. > 후에 람다식 표현 적용

결과적으로 람다식의 모형과 함수형 인터페이스로 인스턴스를 만드는 방식과 모형이 동일하고 실제로 이 둘은 같다. 람다식은 이러한 함수형 인터페이스를 베이스로 만들어진 것이다. 

 

표준 API 함수 인터페이스

자바에서는 미리 정의된 함수형 인터페이스 API를 제공한다. 

 

1. Comsumer : 소비만 한다. 리턴이 없는 구조이다. 

 - 메서드 이름 : accept

- T -> void
- Consumer<T>
- BiConsumer<T, U> : 매개변수 갯수가 2개 

 

2. Supplier : 공급만 한다. 소비가 없다. 매개변수가 없다. 

 - 메서드 이름 : get

- () -> T 
- Supplier<T>

 

3. Function : 매개변수와 리턴값이 있는 함수다. 함수의 개념을 생각하면 된다. 

 - 메서드 이름 : apply
- Function<T, R>
- BiFunction<T, U, R> : 매개변수 갯수가 2개 

 

4. Operator

- 메서드 이름 : identity

- T -> T
- UnaryOperator<T>
- BinaryOperator<T>
- Function 하위셋

 

5. Predicate : true/false 인지 판단하는 의미로 boolean 리턴형을 가진다. 

- 메서드 이름 : test

- T -> boolean 
- Predicate<T>
- BiPredicate<T, U>
- Function 하위셋

- true/false가 결과로 나오는 형태 

 

6. Comparator : 비교 메서드를 구현, sort 함수에서 인자로 넣는 경우가 있음

- 메서드 이름 : compare  

- (T, T) -> int

 

7. Runnable : 실행 가능한 이라는 의미를 가진다. 매개변수도 없고 반환형도 없는 메서드를 가짐

- 메서드이름 : run

- () -> void

 

8.Callble : 호출 가능한 의미를 가진다. 호출해서 결과를 반환하는 리턴값을 가짐 

- 메서드 이름 :call

- () -> T

 

 

 

'자바' 카테고리의 다른 글

JVM 구조  (0) 2023.07.23

개념

싱글톤 패턴은 필요한 객체의 인스턴스를 오직 한개만 제공하는 클래스를 만드는 방법이다. 

 

시스템 런타임, 환경 세팅에 대한 정보 등, 인스턴스가 여러개 일 때 문제가 생길 수 있는 경우가 있다.

 

인스턴스를 오직 한개만 만들어 제공하는 클래스가 필요할 때 이 패턴을 사용할 수 있다.

 

이 패턴의 목적은 두가지가 있다.

 

1. 인스턴스를 오직 하나만 만들수 있어야 한다.

 

2. 그렇게 만들어진 하나의 인스턴스에 글로벌하게 접근할 수 있어야 한다. 

 

일반적으로는 아래와 같이 클래스를 만들고 객체를 두번 생성하면 두 클래스의 값은 다르다.

 

public class Settings {}
public class App {

	public static void main(String[] args) {
    	
        Settings setting1 = new Settings();
        Settings setting2 = new Settings();
        System.out.println(setting1 != setting2);  // 결과는 true
    	    
    }
    
}

싱글톤 패턴에서는 객체를 한개만 생성하게 해야하며 밖에서 new를 쓰게 하는 순간 여러개의 객체를 생성하게 만들 수 있기 때문에 밖에서 new를 사용하지 못하게 해야 한다. 

 

☞ 그러한 방법에 대한 해결책으로는 'private 생성자'를 만들면 된다.

  • 접근 권한을 걸어서 생성자 자체를 밖에서 만들지 못하게 하는 것이다.
  • 또한 객체를 만들더라도 단 한번만 클래스 내부에서 new를 호출하도록 해야 한다. 

또한 이렇게 내부적으로 만든 객체를 글로벌하게 접근할 수 있는 방법을 제공해주어야 한다. 

 

☞ 생성된 객체를 글로벌하게 접근할 수 있게 하기 위한 방법으로 'static' 키워드를 사용해서 접근하는 메서드를 만든다.

 

Naive한 싱글턴 패턴

 

결과적으로 위의 해결방법을 적용하면 아래와 같은 Settings 클래스가 생성된다. 이것이 가장 Naive한 싱글턴 패턴이라 말할 수 있다. 

public class Settings {

	private static Settings instance;

	private Settings() {}
	public static Settings getInstance() {
    	if(instance == null){
        	instance = new Settings();
        }
    	return instance;
    }
    
}

다음 코드의 결과는 false가 나오게 된다.

public class App {

	public static void main(String[] args) {
    	
        Settings setting1 = Settings().getInstance();
        Settings setting2 = Settings().getInstance();
        System.out.println(setting1 != setting2);  // 결과는 false
    	    
    }
    
}

getInstace()를 여러번 호출하더라도 하나의 인스턴만을 반환하게 된다. 그래서 두 객체는 같게 된다.

 

인스턴스 객체 자체를 메모리에 한번 할당되어 프로그램 종료시 해제되는 Static 키워드를 붙이고 private 생성자를 의도적으로 사용하여 외부에서 생성자를 참조 못하게 하는 방식으로 해결한 것이다. 

 

스레드 세이프 문제

 

하지만 이 방법에는 웹을 만들 때 많이들 쓰는 '멀티스레드 환경'에서 사용하기엔 심각한 문제가 있다.

 

예시

위의 그림에서 빨간 스레드, 파란 스레드가 있다고 치자. 여기서 빨간 스레드가 if문을 먼저 진입하고 파란 스레드가 다음으로 if문을 진입한다고 했을 때 new는 두번 호출된다. 그래서 문제가 있다는 것이다. 그러면 이걸 어떻게 해결할까?

 

☞ 메서드를 동기화시키자. 방법은 여러가지가 있다. 

  • synchronized 키워드 사용하기 : 이 방법은 동기화를 보장하긴 하지만 한쪽이 if문 안에 있을 때 lock을 걸어버리기 때문에 부가적인 성능의 부하가 생길 여지가 있다.
  • 이른 초기화(Eager initialization ) 방법 사용하기 : 인스턴스를 private 선언과 동시에 초기화시켜주고 getInstance에서는 리턴만 해주는 방식이다. 이 방식은 인스턴스 자체가 메모리를 많이 먹고 길고 오래걸리고 잘 안쓰면 비효율적인 방식이다. 
  • Double Checked Locking 사용하기 : 두번의 if문을 넣고어서 객체 존재 여부를 체크하고 첫번째 if문 안쪽에 synchronized 키워드로 동기화시키는 방법인데 volatile 키워드를 써야 동작하고 코드 짜는게 귀찮다...

권장하는 방식 

 

static inner 클래스를 사용하는 방법 

 

다음과 같이 사용하면 멀티스레드 환경에서도 안전하고 getInstance() 호출되는 시점에서 클래스가 로딩되서 인스턴스를 미리 안만들어도 된다. 

public class Settings{
    private Settings(){}

    private static class SettingsHolder {
        private static final Settings INSTANCE = new Settings();
    }

    public static Settings getInstance() {
        return SettingsHolder.INSTANCE;
    }
}

 

하지만 ... 이방법도 Reflection API를 쓰면 싱글톤을 깨트릴 수 있다. Reflection API가 제공하는 setAccessible() 메서드를 써버리면 private도 접근이 가능하다. 이 방식으로 강제로 생성자를 호출시켜버리는 것이다. 이것에 대한 해결책으로 enum으로 싱글턴을 구현하는 방식도 있는데 이래버리면 구현이 제한적인면이 있어서 개인적으로는 또 좋지 않다고 생각한다. 그래서 일단은 static inner 방식까지만 기억해두자

 

출처 > 인프런 - 백기선 - 디자인 패턴 

+ Recent posts