-
Notifications
You must be signed in to change notification settings - Fork 5
9주차 [Spring] Spring과 Spring Boot, 빌드 관리 도구 #64
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
Open
leeejuhyeong
wants to merge
10
commits into
no-study-no-future:leeejuhyeong
Choose a base branch
from
leeejuhyeong:spring
base: leeejuhyeong
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
1f77f4d
create: [Spring] 다양한 의존관계 주입(#6)
kludio 8876763
create: [Spring] 생성자 주입을 사용해야하는 이유(#8)
leeejuhyeong b913337
Delete 의존성 주입 방법.md
leeejuhyeong 3cb2f6e
create: [Spring] 의존관계 주입 방법(#6)
leeejuhyeong 54e2792
docs: 의존관계 주입 방법.md 수정 #6
leeejuhyeong 8c1aca7
docs: 의존관계 주입 방법.md 수정 #6
leeejuhyeong d83cdab
docs: 생성자 주입을 사용해야하는 이유.md 수정 #8
leeejuhyeong 50dd7b7
create: [Database] 인덱스를 사용하는 이유 #12
leeejuhyeong 099bccd
update : [Database] 인덱스를 사용하는 이유 #12
leeejuhyeong d2de1eb
create: [Spring] Spring과 Spring Boot, 빌드관리도구 #63
leeejuhyeong File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| # 인덱스를 사용하는 이유(장단점) | ||
| ## 요약 | ||
| > 인덱스는 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다. | ||
| > 사용 시 테이블 조회 속도를 높여 DB 성능을 향상시키며, Full Scan하지 않아 시스템 부하를 줄여줍니다. | ||
| > 하지만 항상 정렬된 상태로 유지해야하기에 추가적인 쓰기작업이 필요하며 이를 저장하기 위한 저장공간이 필요합니다. 때문에 잘못 사용할 경우 성능 저하의 역효과를 발생시킵니다. | ||
|
|
||
|
|
||
| ## 인덱스(Index)란? | ||
| - 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조. | ||
| - 추가적인 쓰기 작업과 저장공간을 활용 | ||
| -> 이를 관리하기 위해 DB에 ~~약 10%에 해당하는~~ 저장공간 필요 | ||
| - **PK는 자동으로 Index가 생성됨** -> NHN 기출 | ||
|  | ||
|
|
||
| > 인덱스 없이 조회하면 모든 튜플(레코드)를 검색하지만 인덱스를 사용한다면 인덱스를 탐색하고 일치할 시에 해당 튜플로 데이터를 검색. -> 속도 **up** | ||
|
|
||
|
|
||
| ## 인덱스를 사용하는 이유 | ||
| - 인덱스 테이블은 데이터들이 정렬되어 있음! -> **정렬과 연관지어 기억하자** | ||
|
|
||
| ### 조건 검색 Where 절의 효율성 | ||
| - 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건(where)에 맞는 데이터를 빠르게 찾아낼 수 있음 | ||
|
|
||
| ### 정렬 Order by 절의 효율성 | ||
| - 이미 정렬되어 있기 떄문에 order by에 의한 Sort과정을 피할 수 있음 | ||
|
|
||
| ### MIN, MAX의 효율적인 처리 가능 | ||
| - MIN값과 MAX값을 레코드의 시작값과 끝 값 한 건씩만 가져오면 되기에 Full Scan보다 효율적 | ||
|
|
||
|
|
||
| ## 인덱스의 장단점 | ||
| ### 장점 | ||
| - 테이블을 조회하는 속도와 그에 따른 성능을 향상 | ||
| - 전반적인 시스템의 부하를 줄임(Full Scan을 안해서) | ||
|
|
||
| ### 단점 | ||
| - 인덱스를 관리하기 위해 DB의 ~~약 10%에 해당하는~~ 추가적인 저장공간 필요 | ||
| - 인덱스를 관리하기 위해 추가 작업 필요 | ||
| - 잘못 사용할 경우 성능 저하의 역효과 발생 | ||
|
|
||
|
|
||
| ## 인덱스 관리 | ||
| - Index를 항상 **최신의 데이터를 정렬된 상태로 유지**해야 원하는 값을 탐색 할 수 있음 | ||
| - INSERT, UPDATE, DELETE(데이터 추가, 수정, 삭제) 수행 시 정렬 필요! -> 부하**UP** | ||
| - INSERT, UPDATE, DELETE 시 추가적인 연산 필요 | ||
| -> 부하를 최소화하기 위해 데이터 삭제라는 개념에서 **인덱스를 사용하지 않는다** 라는 작업으로 대신함 | ||
| - INSERT : 새로운 데이터에 대한 인덱스 추가 | ||
| - DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 진행 | ||
| - UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가 | ||
|
|
||
|
|
||
| ## 인덱스 생성 전략 | ||
| - 조건절에 자주 등장하는 컬럼(호출 빈도가 높음) | ||
| - 같거나 크고, 작음으로 자주 사용되는 컬럼(where 또는 order by에서 쓰이는 컬럼) | ||
| - 중복되는 데이터가 최소한인 컬럼(분포도가 좋다 = 데이터가 서로 다르고 넓게 퍼져 있다) | ||
| - 조인 조건으로 자주 사용되는 컬럼 | ||
|
|
||
|
|
||
| ## 인덱스 자료구조 | ||
| ### 해시테이블 | ||
| - key : 데이터(= 컬럼의 값) | ||
| - value : 데이터의 위치 | ||
| - 장점 | ||
| - 빠른 데이터 탐색에 유용 | ||
| - 시간 복잡도 O(1) | ||
| - 단점 | ||
| - 등호 연산에만 특화 | ||
| - DB는 부등호(>, <) 연산이 많아서 **사용 부적합** | ||
|  | ||
|
|
||
| ## B+ Tree | ||
| - 대부분의 DB 인덱싱 자료구조 | ||
| - 특징 | ||
| - 리프노드에만 인덱스와 함께 데이터를 갖고있고, 나머지 노드들은 인덱스만을 가짐 | ||
| - 리프노드들은 연결리스트로 이루어짐 -> 탐색이 0번노드부터 일어나는 연결리스트에 비해 시간 효율이 좋음!(log2(N)) | ||
| - 데이터 노드의 크기는 인덱스 노드와의 크기와 같지 않아도 됨 | ||
| - 예시 | ||
| - 인덱스 | ||
|  | ||
|
|
||
| - B+ Tree | ||
|  | ||
|
|
||
| > BTree : 모든 노드에 데이터를 담음 | ||
| > 리프노드 : 자식이 없는 노드. 잎이라고도 함 | ||
| > B+ Tree 알고리즘에 대해서는 추후 정리할 예정입니다. | ||
|
|
||
|
|
||
|
|
||
| ## TMI : 결합 인덱스 | ||
| - 두 개 이상의 컬럼을 합쳐서 인덱스를 만드는 것 | ||
| - 단일 컬럼으로는 분포도가 나쁘지만, 여러 개의 컬럼을 합친다면 좋은 분포도를 가지며, where절에서 and 조건에 많이 사용되는 컬럼을 결합 인덱스로 생성함 | ||
|
|
||
| ### 결합 인덱스 컬럼 생성 전략 | ||
| - where절에서 and 조건으로 자주 결합되고, 결합할 시 분포도가 좋아지는 컬럼 | ||
| - 다른 테이블과 조인의 연결고리로 자주 사용되는 컬럼 | ||
| - order by에서 자주 사용되는 컬럼 | ||
| - 하나 이상의 키 컬럼 조건으로 같은 테이블의 컬럼들이 자주 조회될 때 | ||
|
|
||
| ### 예시 | ||
| - 결합 인덱스 생성 예시 | ||
| `create index emp_pay_idx on emp_pay(급여년월, 급여코드, 사원번호);` | ||
| - 결합 인덱스 사용 예시 | ||
| ``` | ||
| select * from emp_pay where 급여년월 = '202107'; | ||
| select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여'; | ||
| select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여' and 사원번호 = '20210401'; | ||
| ``` | ||
|
|
||
| > 단 급여코드만을 검색할 때는 결합 인덱스의 첫 번째 컬럼인 급여년월의 조건식이 없기 때문에 결합 인덱스로 조회하지 않음! -> 급여년월, 급여코드, 사원번호의 순서대로 조회 | ||
| - 결합 인덱스 효율성 감소 | ||
| 1. LIKE 검색 : 2021%같이 검색할 경우 2021에 해당하는 모든 급여코드, 정기급여로 생성된 결합 인덱스를 조회해서 B*Tree에서 조회하기 어려움 | ||
| 2. 결합 인덱스 칼럼 순서(이하 급여년월(1), 급여코드(2), 사원번호(3) 컬럼을 숫자로 말하겠습니다) | ||
| - 1, 3 / 2 / 2, 3 / 3 으로 조회할 경우 결합 인덱스 순서대로 조회하지 않아서 Full Scan이 발생합니다 | ||
|
|
||
|
|
||
| - 출처 | ||
| - [Database 인덱스(index)란? - MangKyu’s Diary](https://mangkyu.tistory.com/96) | ||
| - [DB 데이터베이스 인덱스(Index) 란 무엇인가?](https://coding-factory.tistory.com/746) | ||
| - [자료구조 그림으로 알아보는 B+Tree](https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Plus-Tree) |
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| # Spring과 Spring Boot, 빌드 관리 도구 | ||
| ## 요약 | ||
| - Spring Framework란 자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크 | ||
| - Spring Boot는 Spring Framwork를 사용하기 위한 설정을 자동화하여 사용자가 편하게 스프링을 활용할 수 있게 도움 | ||
| - 빌드 관리 도구는 애플리케이션 개발 시 외부 라이브러리들을 관리해주는 것으로 Maven, Gradle 등이 있음 | ||
|
|
||
| ## Spring Framework란 | ||
| - 자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크 | ||
| - 특징 | ||
| - 경량 컨테이너 : 각각의 객체 생성, 소멸과 같은 라이프 사이클을 관리하며 스프링으로부터 필요한 객체를 얻어옴 | ||
| - 스프링 컨테이너 : 스프링의 빈(객체)을 관리 | ||
| - ApplicationContext(AnnotationApplicationContext) | ||
| - IoC(제어의 역행) : 느슨한 결합, 제어권이 프레임워크에 있어 필요에 따라 스프링에서 사용자의 코드를 호출 | ||
| - DI(의존성 주입)를 통한 객체 간의 관계 구성 : 특정 객체가 필요로 하는 객체를 외부에서 결정(주입)(AppConfig) | ||
| - AOP(관점지향 프로그래밍) 지원 : 공통적으로 사용하는 기능을 분리(Filter, Interceptor, AOP) | ||
|
|
||
| > Bean : Spring에 의해서 생성되고 관리되는 자바 객체 | ||
| > IoC, DI를 통해 OCP(개방폐쇄법칙)를 지킴 -> 스프링 프레임 | ||
|
|
||
| ## Spring과 Spring Boot의 차이 | ||
| ### Spring의 문제점 | ||
| - 기능이 많은 만큼 환경설정이 복잡 | ||
| - XML 설정 등 | ||
| - Spring MVC, Hibernate 코어 및 Log4j와 같은 유사한 요구사항들의 중복 | ||
|
|
||
| ### Spring Boot | ||
| - 스프링 프레임워크를 사용하기 위한 설정의 많은 부분을 자동화 | ||
| - 사용자가 편하게 스프링을 활용할 수 있도록 도움 | ||
| - Spring 프레임워크와의 차이점 | ||
| - Starter를 통한 Dependency 자동화 | ||
| - Embed Tomcat으로 인한 Tomcat 설치 및 버전 관리 수고로움 X | ||
|
|
||
|
|
||
| ## Maven, Gradle? | ||
| ### 빌드 관리 도구 | ||
| - 애플리케이션 개발 시 다양한 외부 라이브러리들이 필요 | ||
| - 필요한 라이브러리들을 설정파일을 통해 자동으로 다운로드해주고, 관리해주는 도구 | ||
|
|
||
| ### Maven | ||
| - Apache Maven, 자바용 프로젝트 관리 도구 | ||
| - 라이브러리들과 연관된 라이브러리들까지 모두 연동되어 관리 | ||
| - POM(Project Object Model) 구조 | ||
| - pom.xml | ||
| - 프로젝트 정보, 빌드 설정, 빌드 환경, pom 연관 정보 | ||
|
|
||
| ### Gradle | ||
| - 안드로이드 앱의 공식 빌드 시스템 | ||
| - Maven에 비해 빌드 속도 10~100배 가량 빠름 | ||
| - Java, C/C++, Python 등 지원 | ||
| - 별도의 빌드 스크립트(Groovy)를 통하여 사용할 애플리케이션 버전, 라이브러리 등의 항목을 설정 | ||
|
|
||
| ### Maven, Gradle 차이점 | ||
| - 가독성 | ||
| - pom.xml보다 build.gradle이 더 간결하고 가독성이 좋음 | ||
| - 빌드 시간 단축 | ||
| - Gradle의 경우 이미 업데이트된 테스크에 대해 작업이 실행되지 않는 incremental build를 허용하기에 빌드 시간이 단축 | ||
| - 대규모 프로젝트 | ||
| - 가독성, 빌드 시간 단축 등의 이유로 대규모 프로젝트일 경우 Gradle이 더 적합하다고 함 | ||
|
|
||
| ## 출처 | ||
| - [번역글 스프링 vs 스프링 부트 차이 비교하기!](https://sas-study.tistory.com/274) | ||
| - [Spring 과 Spring Boot 차이](https://velog.io/@courage331/Spring-%EA%B3%BC-Spring-Boot-%EC%B0%A8%EC%9D%B4) | ||
| - [Spring 스프링 프레임워크(Spring Framework)란?](https://steady-coding.tistory.com/457) | ||
| - [메이븐(Maven)과 그래들(Gradle)의 개념 및 비교 :: 슬기로운 개발생활😃](https://dev-coco.tistory.com/65) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| # 생성자 주입을 사용해야하는 이유 | ||
| # 요약 | ||
| - [객체의 불변성 확보](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=1.%20%EA%B0%9D%EC%B2%B4%EC%9D%98%20%EB%B6%88%EB%B3%80%EC%84%B1%20%ED%99%95%EB%B3%B4) | ||
| - [테스트 코드 작성 용이](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=2.%20%ED%85%8C%EC%8A%A4%ED%8A%B8%20%EC%BD%94%EB%93%9C%EC%9D%98%20%EC%9E%91%EC%84%B1) | ||
| - [final키워드 작성으로 실수를 줄이고 Lombok과의 연계가 좋다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=3.%20final%20%ED%82%A4%EC%9B%8C%EB%93%9C%20%EC%9E%91%EC%84%B1%20%EB%B0%8F%20Lombok%EA%B3%BC%EC%9D%98%20%EA%B2%B0%ED%95%A9) | ||
| - [순환 참조 에러를 사전에 방지한다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=4.%20%EC%88%9C%ED%99%98%20%EC%B0%B8%EC%A1%B0%20%EC%97%90%EB%9F%AC%20%EB%B0%A9%EC%A7%80) | ||
|
|
||
|
|
||
| # 1. 객체의 불변성 확보 | ||
| - 대부분 의존 관계 주입은 애플리케이션 종료시점까지 변하면 안됨! | ||
| - Setter를 열어두는 것은 좋은 설계 방법이 아님(누군가 실수로 변경할 수 있음) | ||
| -> OCP(Open/closed principle) 위배 | ||
| - 생성자 주입은 생성 시 딱 1번만 호출됨으로 불변하게 설계할 수 있음 | ||
| - final 키워드 설정 가능(불변임으로) | ||
|
|
||
|
|
||
| # 2. 테스트 코드의 작성 | ||
| ## 생성자 주입이 아닐 경우 | ||
| - 필드 주입을 사용한다면 테스트 환경은 실제 코드의 DI 프레임워크 위에서 동작하지 않고, 순수한 자바 코드로 동작 -> **Null Point Exception 에러 발생, 테스트 하는 것이 불가능** | ||
|
|
||
| ### 실제 코드 | ||
| ``` | ||
| @Service | ||
| public class UserServiceImpl implements UserService { | ||
|
|
||
| @Autowired | ||
| private UserRepository userRepository; | ||
|
|
||
| public UserRepository getUserRepository() { | ||
| return userRepository; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 테스트 코드 | ||
| ``` | ||
| public class UserServiceTest { | ||
| @Test | ||
| public void injectionTest() { | ||
| UserService userSerivce = new UserServiceImpl(); | ||
| UserRepository ur = userService.getUserRepository(); | ||
| System.out.println(ur); | ||
| } | ||
| ``` | ||
|
|
||
| > DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 | ||
|
|
||
| - 위의 문제를 해결하기 위해선 Setter를 사용하면 되지만**, 싱글톤 패턴을 해칠 수 있다.** 또한 수정자 주입과 다를 바가 없으면서 수정자 주입 역시 **OCP 위배**한다는 문제가 있음 | ||
|
|
||
| > OCP(Open/closed principle) : 개방-폐쇄 원칙, 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다. | ||
|
|
||
|
|
||
| ## 생성자 주입일 경우 | ||
| - 의존 관계 주입이 누락될 경우 **컴파일 오류**가 발생 | ||
| - 어떤 값을 필수로 주입해야하는 지 확실하게 알 수 있음! | ||
|
|
||
| ### 실제 코드 | ||
| ``` | ||
| @Service | ||
| public class UserServiceImpl implements UserService { | ||
|
|
||
| private UserRepository userRepository; | ||
|
|
||
| @Autowired | ||
| public UserServiceImpl(UserRepository userRepository) { | ||
| this.userRepository = userRepository; | ||
| } | ||
|
|
||
| public UserRepository getUserRepository() { | ||
| return userRepository; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 테스트 코드 | ||
| ``` | ||
| public class UserServiceTest { | ||
| @Test | ||
| public void injectionTest() { | ||
| UserService userSerivce = new UserServiceImpl(); | ||
| UserRepository ur = userService.getUserRepository(); | ||
| System.out.println(ur); | ||
| } | ||
| ``` | ||
|
|
||
| > 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` | ||
|
|
||
|
|
||
| # 3. final 키워드 작성 및 Lombok과의 결합 | ||
| ## final 키워드 작성 | ||
| - 생성자 주입은 final 키워드 사용 가능 | ||
| -> 값 설정 누락 시 컴파일 시점에 오류 발생 | ||
| - 누락된 의존성 확인이 빠름! | ||
|
|
||
| ## Lombok과의 결합 | ||
| - `@RequiredArgsConstructor` | ||
| -> final이 붙은 필드(변수)를 모두 모아 생성자를 자동으로 생성 | ||
| - 필드 주입보다 더 간결한 코드! | ||
|
|
||
| > **최종 코드** | ||
| ``` | ||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class UserServiceImpl implements UserService { | ||
|
|
||
| private final UserRepository userRepository; | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
| # 4. 순환 참조 에러 방지 | ||
| ## 필드 or 수정자 주입의 경우 | ||
| - 예시 (닭은 알을 낳고, 알은 닭으로 부화하고) | ||
| ``` | ||
| @Component | ||
| public class Chicken { | ||
| @Autowired Egg egg; | ||
|
|
||
| public void layEgg() { | ||
| egg.hatch(); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ``` | ||
| @Component | ||
| public class Egg { | ||
| @Autowired Chicken chicken; | ||
|
|
||
| public void hatch() { | ||
| chicken.layEgg; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| > 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 | ||
|
|
||
| ## 생성자 주입의 경우 | ||
| - 애플리케이션 구동 시점(객체 생성 시점)에 컴파일 오류를 발생시켜 순환 참조 에러를 방지 | ||
|
|
||
| ``` | ||
| Description: The dependencies of some of the beans in the application context form a cycle: | ||
| ┌─────┐ | ||
| | chicken defined in file [(경로)/Chicken.class] | ||
| ↑ ↓ | ||
| | egg defined in file [(경로)\Egg.class] | ||
| └─────┘ | ||
| ``` | ||
|
|
||
| > 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. | ||
|
|
||
| ## 출처 | ||
| - [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
embedded tomcat이 더 적절하다 생각이 드네요오There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 이런 오타가.. 수정하겠습니다