LocalDate ํฌ๋งท ์ค๋ฅ๋ก ์์๋ OpenFeign ์ Auto Configuration ํ์
๊ฐ์
OpenFeign์ ์ฌ์ฉํด admin ์๋ฒ์ core ์๋ฒ ๊ฐ์ HTTP ํต์ ์ ํ๋ ์ค, ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
- admin ์๋ฒ์์ LocalDate ํ์ ์ yyyy-MM-dd ํฌ๋งท์ผ๋ก ์์ฒญ์ ๋ณด๋์ต๋๋ค.
- ๊ทธ๋ฌ๋ core ์๋ฒ์์๋ LocalDate ํฌ๋งท์ด yyyy-MM-dd ๋ฅผ ๊ธฐ๋ํ์ง๋ง, yy. M. d. ์ผ๋ก ์์ ํฌ๋งท ๋ณํ์ ์คํจํ๋ ์๋ฌ ๋ก๊ทธ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์ด ๋ฌธ์ ๋ ์ฐ์ํํ์ ๋ค ๊ธฐ์ ๋ธ๋ก๊ทธ์์ ์ ์ํ ๋ฐฉ์์ผ๋ก ๊ฐ๋จํ ํด๊ฒฐํ ์ ์์ต๋๋ค:
@Bean
public FeignFormatterRegistrar localDateFeignFormatterRegister() {
return registry -> {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
};
}
ํ์ง๋ง ์ ๋ ์ ์ด๋ฐ ์ฝ๋๊ฐ ํ์ํ์ง, ์ฆ ์ด๋ค ๊ณผ์ ์ ํตํด ํฌ๋งท์ด ๊นจ์ก๋์ง ๊ทธ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ํ์ ํด๋ณด๊ณ ์ถ์์ต๋๋ค.
๊ทธ ๊ณผ์ ์ ์๋์ ์๊ฐํฉ๋๋ค.
1. ๋๋ฒ๊ฑฐ๋ก ์์ธ ์ฐพ๊ธฐ
๋จผ์ @FeignClient๋ก ์์ฒญ์ ๋ณด๋ด๋ ์ชฝ์ ๋ธ๋ ์ดํฌํฌ์ธํธ๋ฅผ ๊ฑธ๊ณ , LocalDate๊ฐ ์ธ์ yyyy-MM-dd → yy. M. d. ํ์์ผ๋ก ๋ฐ๋๋์ง๋ฅผ ์ถ์ ํ์ต๋๋ค.
๋๋ฒ๊น ์ ํตํด SpringMvcContract ํด๋์ค ๋ด๋ถ์์ ํฌ๋งท์ด ๋ณํ๋๋ ๊ณผ์ ์ ํ์ธํ ์ ์์์ต๋๋ค.
๋ ๊น์ด ๋ค์ด๊ฐ ๋ณด๋, ์ต์ข ์ ์ผ๋ก๋ DateTimeFormatterBuilder$CompositePrinterParser ํด๋์ค์์ yyyy-MM-dd ํ์์ด yy. M. d.๋ก ๋ณ๊ฒฝ๋๋ ๊ฒ์ ํ์ธํ ์ ์์์ต๋๋ค.
@FeignClients ์ด๋ ธํ ์ด์ ์ ๊ธฐ๋ณธ ๋์์ด ์ ์ด๋ ๊ฒ ๋์๋์ง ํ์ธํ๊ณ ์ ํฉ๋๋ค.
2. @EnableFeignClients
๋จผ์ , ์ด๋ค @FeignClients ๊ฐ ๋์ํ ์ ์๊ฒ ํ๋ @EnableFeignClients ๋ฅผ ํ์ธํฉ๋๋ค.
์ฌ๊ธฐ์ FeignClientsRegistrar ํด๋์ค๊ฐ ๋์ํ์ฌ, @EnableFeignClients์ ๋ช ์๋ value, basePackages, defaultConfiguration, clients ๊ฐ์ ์ฝ๊ณ ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ํ Bean๋ค์ ๋ฑ๋กํฉ๋๋ค.
์ด ๊ณผ์ ์์ @EnableFeignClients ์ defaultConfiguration ๋ defaults ๋ก FeignClientsConfiguration ์ ์ฌ์ฉํ๋ค๊ณ ํฉ๋๋ค.
3. FeignClientsConfiguration
FeignClientsConfiguration์ ์ดํด๋ณด๋ฉด, ์์ ๋๋ฒ๊น ์ค ๋ณด์๋ SpringMvcContract ํด๋์ค๊ฐ Bean์ผ๋ก ๋ฑ๋ก๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
* SpringMvcContract๋ @FeignClient์์ ์ฌ์ฉํ๋ @RequestMapping, @GetMapping, @RequestParam ๋ฑ์ ์ด๋ ธํ ์ด์ ์ Spring MVC ๋ฐฉ์์ผ๋ก ํด์ํ๋๋ก ๋์์ฃผ๋ ํด๋์ค์ ๋๋ค.
SpringMvcContract ๋ feignContract๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฑ๋ก๋๋ฉฐ, @ConditionalOnMissingBean์ ํตํด Contract ํ์ ์ Bean์ด ๋ฏธ๋ฆฌ ๋ฑ๋ก๋์ด ์์ง ์์ ๊ฒฝ์ฐ ๊ธฐ๋ณธ ๊ตฌํ์ฒด๋ก SpringMvcContract๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
4. ํฌ๋งทํฐ ๋ฑ๋ก ๊ตฌ์กฐ ์ดํดํ๊ธฐ
SpringMvcContract Bean์ด ์์ฑ๋ ๋๋ feignConversionService๋ผ๋ Bean์ด ํจ๊ป ์ฃผ์
๋๋๋ฐ,
์ด feignConversionService๋ ๋ด๋ถ์ ์ผ๋ก feignFormatterRegistrars ๋ฆฌ์คํธ๋ฅผ ๋ฐ๋ณต๋ฌธ์ผ๋ก ์ํํ๋ฉฐ ํฌ๋งทํฐ๋ฅผ ๋ฑ๋กํฉ๋๋ค.
์ด๋ ์ฌ์ฉ๋๋ feignFormatterRegistrars๋ FeignClientsConfiguration์ ๋ฉค๋ฒ ๋ณ์์ด๋ฉฐ, ์ด๊ธฐ์๋ ์๋ฌด ํฌ๋งทํฐ๋ ๋ฑ๋ก๋์ง ์์ ๋น ArrayList๋ก ์ด๊ธฐํ๋์ด ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , ์๋ ์ฌ์ง์ ๋นจ๊ฐ ์ค์์ FormattingConversionService ๋ FormatterRegistry ๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ ์๊ธฐ์
๋นจ๊ฐ์ค์ ๊ฐ๋จํ๊ฒ ์ด๋ ๊ฒ ํ์ํ ์ ์์ต๋๋ค.
registrar.registerFormatters(registry);
์ฌ๊ธฐ์ registrar๋ ํฌ๋งทํฐ๋ฅผ ๋ณด์ ํ ๊ฐ์ฒด์ด๊ณ , registry๋ ์ด ํฌ๋งทํฐ๋ค์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ์ญํ ์ ํฉ๋๋ค.
์ฝ๊ฒ ๋น์ ํ์๋ฉด
registrar : LocalDate๋ฅผ yyyy-MM-dd ๋ก ํฌ๋งทํ๊ณ ์ถ์ด!
registry : ์ข์! ๊ทธ ํฌ๋งท ๋ด๊ฐ ๊ธฐ์ตํด์ ํ์ํ ๋ ์ฌ์ฉํ ๊ป!
์ด์ฒ๋ผ registrar์ registry์ ๊ด๊ณ๋ N : 1 ๋ก, ์ฌ๋ฌ ๊ฐ์ registrar๊ฐ ์กด์ฌํ ์ ์๊ณ , ์ด๋ค์ ํ๋์ registry์ ์ฐจ๋ก๋ก ํฌ๋งทํฐ๋ฅผ ๋ฑ๋กํ๊ฒ ๋ฉ๋๋ค.
์ฆ, feignFormatterRegistrars(registrar)๋ผ๋ ๋ฆฌ์คํธ์ ๋ค์ด ์๋ ์ฌ๋ฌ ํฌ๋งทํฐ๊ฐ ํ๋์ FormattingConversionService (registry)์ ๋ชจ๋ ๋ฑ๋ก๋๋ ๊ตฌ์กฐ์
๋๋ค.
์ด์ ์ด ๊ตฌ์กฐ๋ฅผ ์ดํดํ๋๋, ํ ์ผ์ด ๋ช ํํด์ก์ต๋๋ค. FeignFormatterRegistrar๋ฅผ ์ ์ํด์ ์ํ๋ ํ์ (LocalDate)์ ํฌ๋งท์ ์์ฑํ๊ณ , registry ์ ๋ฑ๋กํด์ฃผ๋ ๊ฒ์ด์๊ณ , ๊ทธ๋ ๊ฒ ํด์ ๋ฑ์ฅํ๋ ์ฝ๋๊ฐ ๋ฐ๋ก ์ฒ์์ ๋ดค๋ ์ฝ๋ ์์ต๋๋ค.
@Bean
public FeignFormatterRegistrar localDateFeignFormatterRegister() {
return registry -> {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
};
}
๋๋ค์์์ registry๋ FormatterRegistry ์ธํฐํ์ด์ค์ด๊ณ , ๊ตฌํ์ฒด๋ก FormattingConversionService ์ ๋๋ค.
์ง๊ธ๊น์ง ๊ฐ์์ ํด๋นํ๋ ์ค๋ช ์ด์๊ณ , ์ถ๊ฐ๋ก OpenFeign ๋ด๋ถ ์ฝ๋๋ฅผ ๋ณด๋ฉฐ ์๊ฒ ๋ ๊ฒ๋ค์ ๊ณต์ ํฉ๋๋ค.
๋ฒ์ธ 1. OpenFeign์ ๊ธฐ๋ณธ Client ์ธ Default ๊ฐ์ฒด
OpenFeign์์ ํน๋ณํ ์ค์ ์์ด ์ฌ์ฉํ๋ ๊ธฐ๋ณธ HTTP Client๋ Client.Default ์ด๋ฉฐ, ๋ด๋ถ์ ์ผfh HttpURLConnection์ ์ฌ์ฉํฉ๋๋ค.
HttpURLConnection์ java.net ํจํค์ง์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ ํ์ค ํด๋์ค์ด๋ฉฐ HTTP ์ปค๋ฅ์ ๊ด๋ จ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , HttpURLConnection ๋ ๊ตฌํ ๊ณผ์ ์์ sun.net.www.http.HttpClient๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ฆ, Client ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด์ธ Default ๊ฐ์ฒด๋ HttpURLConnection์ ์ฌ์ฉํ์ฌ HTTP ํต์ ์ ์ํํ๊ณ ์์ต๋๋ค.
๋ฒ์ธ 2. ๋ค๋ฅธ Http Client ๋ฅผ ์ฌ์ฉํ ์ ์์๊น? FeignAutoConfiguration ๋ฅผ ํ์ธํ๊ธฐ
OpenFeign ๊ณต์ ๋ฌธ์์์๋ OkHttpClient or Http2Client or Apache HttpClient5 ์ฌ์ฉํ๋ ค๋ฉด ์์กด์ฑ๊ณผ yml ํ์ผ์ ์ค์ ๊ฐ์ true ํด์ฃผ๋ฉด Feign์ ๊ธฐ๋ณธ ํด๋ผ์ด์ธํธ๋ฅผ ๋ฐ๊ฟ ์ ์๋ค๋ ์ด์ผ๊ธฐ์ ๋๋ค.
To use OkHttpClient-backed Feign clients and Http2Client Feign clients, make sure that the client you want to use is on the classpath and set spring.cloud.openfeign.okhttp.enabled or spring.cloud.openfeign.http2client.enabled to true respectively.
์๋ฅผ ๋ค์ด, OkHttpClient๋ฅผ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ๋ฉด ๋ฉ๋๋ค.
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
# yml
spring.cloud.openfeign.okhttp.enabled=true
์ด๋ ๊ฒ ์ค์ ํ๋ฉด, org.springframework.cloud.openfeign ํจํค์ง์ ์์นํ FeignAutoConfiguration ํด๋์ค๊ฐ ์์์ ์ค์ ํ spring.cloud.openfeign.okhttp.enabled ๊ฐ์ ์ฝ์ด์ OkHttpClient๋ฅผ Feign์ ๊ธฐ๋ณธ ํด๋ผ์ด์ธํธ๋ก ๊ตฌ์ฑํด ์ค๋๋ค.
๊ทธ๋ฆฌ๊ณ , FeignAutoConfiguration์ OkHttpClient๋ฟ๋ง ์๋๋ผ HttpClient 5์ ๊ฐ์ ๋ค๋ฅธ Client ๊ตฌํ์ฒด๋ ์ง์ํ๋ค๋ ๊ฒ์ ๋๋ค. ํนํ HttpClient 5์ ๊ฒฝ์ฐ์๋ yml์ ๋ช ์์ ์ธ enabled ์ค์ ์ true๋ก ํ์ง ์์๋ matchIfMissing = true ์ค์ ์ ํตํด ์์กด์ฑ๋ง ์กด์ฌํ๋ฉด ํด๋น ํด๋ผ์ด์ธํธ๋ฅผ ํ์ฑํํฉ๋๋ค.(Spring Cloud 2023.0.3 ๋ฒ์ ๊ธฐ์ค์ ๋๋ค)
๋ง์น๋ฉฐ
์ด๋ฒ์ ๋ด๋ถ ์ฝ๋๋ฅผ ํ๋ํ๋ ๋ฐ๋ผ๊ฐ๋ฉฐ ๋๋ ์ ์ด ์์ต๋๋ค. ์์ ์ @Enable~, @ConditionalOn~, @ConditionalOnMissingBean, ํน์ AutoConfiguration ์์ ๋ผ์ด๋ธ๋ฌ๋ฆด ์ฐพ์ง ๋ชปํ๋์ง ์ ์ดํดํ์ง ๋ชปํ์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ํ ๋น์ ์คํ๋ง๋ถํธ ๊ฐ์๋ฅผ ๋ค์ผ๋ฉฐ, ์ด๋ฌํ ์ด๋ ธํ ์ด์ ์ด ๋ฌด์์ ์ํด ์กด์ฌํ๋์ง, ๋ค์ด๋ฐ์ ์ ๊ทธ๋ ๊ฒ ๋์๋์ง, META-INF ์ .imports ํ์ผ์ ์ฝ์ด ํ๋ณด๊ตฐ๋ค์ ImportSelector ๋ก ํํฐ๋งํ๋ ๋ฑ์ ์ดํดํ์๊ณ , ์ด ๋๋ถ์ Feign์ ์ฝ๋๋ฅผ ๋ฐ๋ผ๊ฐ ์ ์์ง ์์๋ ์๊ฐํฉ๋๋ค.
๋ด๋ถ ์ฝ๋๋ฅผ ์ฝ๋ ๊ฒ์ ๋ถ๊ฐํผํ๋ค๊ณ ์๊ฐํ๊ธฐ์ ์์ผ๋ก๋ ์ด๋ฐ ๊ณผ์ ์ ํตํด ์ดํด์ ๊น์ด๋ฅผ ๋ํด์ฃผ๊ณ , ๋ฌธ์ ํด๊ฒฐ ๋ฅ๋ ฅ์ ํฅ์ ์ํค๊ณ ์ถ์ต๋๋ค. ๋ง์ง๋ง์ผ๋ก ํ ์ค ํ์ด๋จผ์ธ ์์ Feign์ Default๋ฅผ HttpClient 5๋ก ๋ณ๊ฒฝํ๋ ์ฌ๋ก๋ฅผ ๋ด์ ๊ธ์ธ 'Feign ์ฝ๋ ๋ถ์๊ณผ ์๋ฒ ์ฑ๋ฅ ๊ฐ์ ' ์ ์ถ๊ฐ๋ก ์ฝ์ผ๋ฉด ์ข์ ๊ฒ ๊ฐ์ ๋งํฌ๋ฅผ ์ฒจ๋ถ๊ฐํ๋ฉฐ ๋ง๋ฌด๋ฆฌ ํ๊ฒ ์ต๋๋ค.
์ฐธ๊ณ
- https://github.com/OpenFeign/feign
- https://mvnrepository.com/artifact/io.github.openfeign/feign-okhttp