์ฃผ๋์ด ๊ฐ๋ฐ์์ ์๋ฐ๊ธฐ ํ๊ณ ์๊ฐ์ด ์ ๋ง ๋นจ๋ฆฌ๊ฐ๋ค. ๋ฒ์จ 1๋ ์ค ์ ๋ฐ์ด ์ง๋ฌ๋ค๋๊ฒ ๋ฏฟ๊ธฐ์ง ์๋๋ค ๐ฅน ์ ์ฌ๋ฅผ ๊ฒฐ์ ํ๋ฉฐ ํผ์ ๋์๊ฒผ๋ ์๊ฐ๋ค์ด ์๋ค. 1. ์ฃผ์ด์ง ์ ๋ฌด๋งํผ์ ์ ๋๋ก ์ดํดํ๊ณ ๋๊น์ง ๋งก์ ์ญํ ์ ์ถฉ์คํ ํด๋ด๊ธฐ 2. ์์ฌ ์ํต์ ํ๋ฐํ ํ๊ธฐ 3. ๋ฌด์กฐ๊ฑด์ ์ธ ์์ฉ๋ณด๋ค๋ ๋ด ์ฃผ๊ด์ ๊ฐ์ง๊ณ ๋๋ ทํ๊ฒ ์๊ฒฌ์ ํํํ๊ธฐ ์๊ฐ์ ๋ค๋์๋ณด๋ ๊ทธ๋๋ ๊ฝค ์ค์ฒํ๋ฉฐ ์ด์ฌํ ํ์ฌ์ํ์ ํ๋ค๋ ์๊ฐ์ด ๋ ๋ค. ์ธํด์ ํ ๋๋ณด๋ค ์ ๋ฌด์ ๋์ด๋๊ฐ ๋์์ก๊ณ ์๋ง์ ๋ ๊ฑฐ์ ์ฝ๋๋ค์ ๋ง๋๊ธฐ๋ ํ๊ณ ํฌ๊ณ ์์ ์ฑ๋ฆฐ์ง๋ค์ด ์์๋ค. ๋ฌธ์ ๋ค์ ํ๋์ฉ ํด๊ฒฐํด๋๊ฐ๋ฉฐ ์ค์ค๋ก ์ป๋ ๊นจ๋ฌ์๋ ์์๊ณ ์ด๋์ ๋ ๋ ธํ์ฐ๊ฐ ์๊ธด ๊ฒ ๊ฐ๊ธฐ๋ ํ๋ค. ํ์๋ถ๋ค์ด ๋์์ฃผ์ ์ ์ ๋ฌด์ ์ ์ ์ํ ์ ์์๊ณ ์ถํ์ ๋๊ตฐ๊ฐ ๋ค์ด์จ๋ค๋ฉด ๋๋ ๋ฐ์ ๋์์ ๋จ๋ค์๊ฒ ๋ง..
collections API ์ค ํ๋๋ก ์ปฌ๋ ์ ์ Map ํํ๋ก ๋ณํ์์ผ์ฃผ๋ API ์ด๋ค. associateBy ํจ์์ groupBy ํจ์๋ ์ง์ ๋ key์ ์ํด ์ธ๋ฑ์ฑ๋ ์ปฌ๋ ์ ์ ์์๋ก๋ถํฐ Map์ ๋ง๋ค์ด์ค๋ค. associateBy public inline fun Iterable.associateBy(keySelector: (T) -> K): Map { val capacity = mapCapacity(collectionSizeOrDefault(10)).coerceAtLeast(16) return associateByTo(LinkedHashMap(capacity), keySelector) } ๋งค๊ฐ๋ณ์์๋ T๋ฅผ ์ ๋ฌํ๊ณ key๋ฅผ ๋ฆฌํดํ๋ ๋๋คํจ์ keySelector๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค. ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ key..
Programming Models 1. Annotated Controller Spring MVC์์ ์ฌ์ฉํ๋ ๋ฐฉ์์ WebFlux ์์ ๊ทธ๋๋ก ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. @RequestMapping, @PathVariable, @RestController, @GetMapping ๋ฑ 2. Functional Endpoints Java8์ lambda style routing๊ณผ handling ๋ฐฉ์ (ํจ์ํ ๋ชจ๋ธ) RouterFunction: ์ด๋ค ํธ๋ค๋ฌ๊ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ์ง ๊ฒฐ์ HandlerFunction: ๋ฐ์ธ๋ฉ ๋ถํฐ HTTP ์์ฒญ ์๋ต์ฒ๋ฆฌ ServerRequest์ ServerResponse๋ก ์๋ต์ ํ๋ฉฐ ์๋ธ๋ฆฟ ์ ์ฝ์ด ์๊ณ ๋ฆฌ์กํฐ๋ธ ํ์ ์ ์ง์ํ๋ค. Spring WebFlux์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ 2๊ฐ์ ๊ฐ๋ฐ ..
Spring Actuator๋? ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ๋ชจ๋ํฐ๋ง, Metric ์์ง์ ์ํ Http Endpoint๋ฅผ ์ ๊ณตํด์ฃผ๋ ๋ชจ๋์ด๋ค. (์์ฝํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ๋ฅผ ์ ์ฒด์ ์ผ๋ก ์ ์ ์๋๋ก ๋์์ฃผ๋ ๊ธฐ๋ฅ!) // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator implementation 'org.springframework.boot:spring-boot-starter-actuator:3.0.1' ๋ค์๊ณผ ๊ฐ์ด dependency๋ง ์ถ๊ฐํด์ฃผ๋ฉด ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. Ex) spring ์ค์ yaml ํ์ผ์ ์๋์ ๊ฐ์ด ์ด๋ค endpoint๋ค์ ํฌํจํ ์ง ๋ช ์ํด์ฃผ๋ฉด ๋๋ค. management: endp..
๊ธฐ์กด์ ํ๋ ๊ฒ ์ฒ๋ผ http.requestMatchers("/h2-console/**").permitAll() ๋ก h2-console์ ๋ํ ์ ๊ทผ์ ํ์ฉํด์ฃผ๋ ค๊ณ ํ์ง๋ง ๊ณ์ํด์ 403(forbidden) ์๋ฌ๊ฐ ๋ฌ๋ค. ๊ตฌ๊ธ๋ง์ ํตํด ํด๊ฒฐํ ๊ฒฐ๊ณผ @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests() .requestMatchers("/users/**").permitAll() .and() .authorizeHttpRequests(auth -> auth .requestMatchers(AntPathRequestMatcher.antMatcher("/h2-console/..
Coroutine Context ์ฝ๋ฃจํด์ ํญ์ Coroutine Context๋ก ๊ตฌ์ฑ๋ ์ฝํ ์คํธ ์์์ ์คํ๋๋๋ฐ, ์ด ์ฝํ ์คํธ๋ Dispatchers์ Job์ผ๋ก ๊ตฌ์ฑ๋๋ค. Dispatchers๋ ์ฝ๋ฃจํด์ด ์คํ๋ ์ค๋ ๋๋ฅผ ์ง์ ํ๋ ์ญํ Default : CPU์์ ๋ง์ ์ฐ์ฐ์ด ํ์ํ ์ฒ๋ฆฌ ๋์์์ ๊ฐ๋ฅํ ์ต๋ ๊ฐ์๋ CPU ์ฝ์ด ์์ ๊ฐ๋ค. IO : ํ์ผ ์ ์ถ๋ ฅ, ๋คํธ์ํฌ ์ฝ ๋ฑ ์ค๋ ๋๊ธฐํ๋ ์ํฉ์ผ ๋ Blocking IO์ฉ ๊ณต์ ์ค๋ ๋ํ์์ ๋์ Default์ ์ค๋ ๋๋ฅผ ๊ณต์ ํ๋ฏ๋ก withContext์์ Dispatcher ๋ณ๊ฒฝ ์, ์ปจํ ์คํธ ์ค์์นญ ํ์ง ์๊ณ ๋์ผํ ์ค๋ ๋์์ ์คํ๋จ Main: ์ฝ๋ฃจํด์์ ์ฒ๋ฆฌ๋ ๊ฐ์ UI์ ๋ฐ์ํ ๋ ๋ฉ์ธ์ค๋ ๋์์ ๋์ UnConfined ๋ฉ์ธ์ค๋ ๋์์ ๋์ C..
Reified ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ค๋ฆญ ํจ์์์ Runtime์ ํ์ ์ ๋ณด๋ฅผ ์ ์ ์๋ค. (๋ณดํต์ ์ปดํ์ผ ์์๋ง ํ์ ์ ์ ์ ์๊ณ ๋ฐํ์์์ ํ์ ์ ๋ณด๋ ์กด์ฌํ์ง ์๊ฒ ๋๋ค.) ์ฆ, ๋ฐํ์์์๋ ํ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์ธ์คํด์ค๋ฅผ ์ฐพ๊ธฐ๊ฐ ์ฝ๋ค. reified ๋ inline fun๊ณผ ํจ๊ป ์ฌ์ฉ๋๋ฉฐ ํจ์์ ๋งค๊ฐ๋ณ์๋ก T ํ์ ํด๋์ค๋ฅผ ๋ฐ๋ ๊ฒ์ ์๋ตํ ์ ์๋ค. ์ถ๊ฐ์ ์ผ๋ก T ํด๋์ค๋ฅผ ๋๊ฒจ์ค ํ์๊ฐ ์๋ค๋ ์ ์ด ์ข์ ๊ฒ ๊ฐ๋ค. ๋ค์์ R2dbcEntityTemplate ์ฟผ๋ฆฌ ์คํ์ ์ํ ํจ์์ด๋ค. ๊ธฐ์กด ์ฝ๋) private fun executeQuery(build: Select, entityClass: KClass): Flow = r2dbcEntityTemplate.query( QueryBuil..
Kotest์๋ ์ ํ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฌ๋ฌ๊ฐ์ ์ธํฐํ์ด์ค ํจ์๋ค์ด ์กด์ฌํ๋๋ฐ ๋ํ์ ์ผ๋ก @beforeSpec @beforeContainer @beforeTest @beforeEach .. ๋ฑ์ด ์กด์ฌํ๋ค. ํ ์คํธ ์๋ช ์ฃผ๊ธฐ์ ์ด๋ ํ ์ ํ ์ธํ ์ ํด์ฃผ์ด์ผ ํ๋๊ฒฝ์ฐ ์ฌ์ฉํ๋ค. ์๋ฅผ ๋ค๋ฉด ํ ์คํธ ์ปจํ ์ด๋ ์คํ, ๋ฐ์ดํฐ ์ฝ์ ๋ฑ๋ฑ! ์ด๋ค function์ ์ฌ์ฉํ๋์ ๋ฐ๋ผ ํ ์คํธ ๊ณผ์ ๊ณผ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง ์ ์๊ธฐ ๋๋ฌธ์ ํ์์ ๋ง๊ฒ ๊ณจ๋ผ ์ฌ์ฉํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค. Function Description @beforeEach ๊ฐ testcase ๋ง๋ค ํธ์ถ๋๋ค. @beforeTest ๊ฐ testcase ๋ง๋ค ํธ์ถ๋๋ค. @beforeContainer ๊ฑฑ context๋ง๋ค ํธ์ถ๋๋ค. @beforeSpec ํ๋์ ํ ์คํธ spec (FunS..
์ฐ๊ด๋ ์ํฐํฐ์ ๋ํด ์ง์ฐ๋ก๋ฉ์ผ๋ก ์ค์ ์ ํด์ฃผ๋ฉด ์ผ๋ฐ์ ์ธ ์กฐํ ์ฟผ๋ฆฌ์์๋ ์ฐ๊ด๋ ์ํฐํฐ๊น์ง ์กฐํํด์ค์ง ์๊ณ ์ฐ๊ด๋ ์ํฐํฐ๋ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ก ์ค์ ์ด ๋๋ค. ์ด๋ ๊ฒ ๋๋ฉด ์ฐ๊ด๋ ์ํฐํฐ์ ๊ฐ์ ์ ๊ทผํด์ผํ ๋ ๋ฐ์ดํฐ๋ง๋ค ์ฟผ๋ฆฌ๊ฐ ํ๋ฒ์ฉ ๋ ์คํ๋์ด N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๊ฒ์ด Fetch Join ์ด๋ค. ์ฐ๊ด๋ ๊ฒ๋ค์ ํ๋ฒ์ ๋ค ๊ฐ์ ธ์ค๋ ๊ฒ์ผ๋ก ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๊ฐ ์๋๋ผ ์ฐ๊ด๋ ์ํฐํฐ๊น์ง ์ค์ ๊ฐ์ผ๋ก ์ ๋ถ ์ฑ์์ค๋ค. (์ฆ, ์กฐ์ธ๋ง ํ๋ ๊ฒ์ด ์๋๋ผ select ์ ์ ์๋ ๊ฐ๋ค๋ ์ ๋ถ ๋ฃ์ด์ฃผ๋ ๊ฒ) EntityGraph - data jpa๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ fetch join ์ jpql ์์ด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค. JpaRepository๋ฅผ ์์๋ฐ๋ repository๊ฐ ์์ ๋ @..
Typically, stubbing argument mismatch indicates user mistake when writing tests. Mockito fails early so that you can debug potential problem easily. However, there are legit scenarios when this exception generates false negative signal: - stubbing the same method multiple times using 'given().will()' or 'when().then()' API Please use 'will().given()' or 'doReturn().when()' API for stubbing. - st..