xml νμμ μμΈ μ€μκ° λμ λ°μ΄ν°λ₯Ό κ°μ Έμμ νμ±νκ³ DBμ μ μ₯νλ λ°κΉμ§ 442μ΄(7λΆ 22μ΄) μμλλ€.
ν μ§μμ λ°μ΄ν°λ₯Ό νμ±νλ λ° 3~10μ΄ κ°λ μμλκ³ , μ΄ 115κ³³μ κ°μ ΈμμΌνλ―λ‘ μ½ 7-8λΆ μμλλ κ²μ΄μλ€.
μλ κ°μ ΈμμΌν λ°μ΄ν°κ° λ§μ μ μ΄μ μ£Όμμ°½μ xmlμ΄ μ‘΄μ¬νλ urlμ μμ²νμ λ 3~5μ΄ μ λ μ§μ°λ¨μ΄ λ°μνκΈ΄ νλ€.
κ½€ μ€λ μκ°μ΄ κ±Έλ € μ±λ₯μ κ°μ μν€κΈ° μν΄ μ¬λ¬ λ°©μλ€μ μλν΄λ΄€λ€...
CompletableFuture λ?
Java 8μμ μΆκ°λ ν΄λμ€λ‘ λΉλκΈ° μ°μ°μ μ²λ¦¬νκ³ μλ£λ κ²°κ³Όλ μμΈλ₯Ό μ²λ¦¬νλ€.
κΈ°μ‘΄μ μλ Java5μ Future μΈν°νμ΄μ€μ νκ³μ μ κ°μ μν¨ κ²μ΄λ€.
πΉ Futureλ ?
π λΉλκΈ° μμ μ κ²°κ³Όλ₯Ό λνλ΄λ λ° μ¬μ©λλ©° μλ£ μνλ₯Ό νμΈνκ±°λ μμ κ²°κ³Όλ₯Ό μ»λ κΈ°λ₯λ§ μ 곡
πΉ Futureμ νκ³μ
- μΈλΆμμ μλ£μν¬ μ μμ β get()μ νμμμ μ€μ μΌλ‘λ§ μλ£ κ°λ₯
- λΈλ‘νΉ λ©μλ νΈμΆ : get() λ©μλ νΈμΆ μ μμ μ΄ μλ£λ λκΉμ§ λκΈ°
- μμ μ‘°ν©μ μ΄λ €μ
- μμΈ μ²λ¦¬ νκ³
Future μΈν°νμ΄μ€λ₯Ό νμ₯νμ¬ μΈλΆμμ μλ£μν¬ μ μμΌλ©° μμ μ½λ°±, μμΈ μ²λ¦¬, λΉλκΈ°μ μΌλ‘ μ¬λ¬ μμ μ μ‘°ν©νλ κΈ°λ₯ λ±μ μ 곡νμ¬ λ³΄λ€ ν¨μ¨μ μΈ λΉλκΈ° νλ‘κ·Έλλ°μ μ§μνλ€.
πΉ λΉλκΈ° μμ μ€ν λ©μλ
- runAsync : λ°νκ°μ΄ μλ κ²½μ°
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// λΉλκΈ° μμ
μν
});
- supplyAsync : λ°νκ°μ΄ μλ κ²½μ°
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// λΉλκΈ° μμ
μν ν κ²°κ³Ό λ°ν
return "μμ
κ²°κ³Ό";
});
πΉ μμ μ½λ°±
- thenApply : λΉλκΈ° μμ μ΄ μλ£λ νμ ν΄λΉ κ²°κ³Όλ₯Ό κ°κ³΅νκ±°λ λ³ν
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenApply(result -> result + " World");
- thenAccept : λΉλκΈ° μμ μ΄ μλ£λ νμ ν΄λΉ κ²°κ³Όλ₯Ό μλΉ
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenAccept(result -> System.out.println("Result: " + result));
- thenRun : λΉλκΈ° μμ μ΄ μλ£λ νμ μΆκ°μ μΈ μμ μν
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("Additional task after completion"));
πΉ μμ μ‘°ν©
- thenCompose : μ΄μ μμ μ κ²°κ³Όμ λ°λΌ λ€μ μμ μννλλ°, λ€μ μμ μ μ΄μ μμ μ κ²°κ³Όλ₯Ό μ λ ₯μΌλ‘ λ°μ
public class Main {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " World"));
future.thenAccept(System.out::println);
}
}
- thenCombine : λ κ°μ CompletableFutureκ° λͺ¨λ μλ£λ νμ λ μμ μ κ²°κ³Όλ₯Ό μ‘°ν©νμ¬ μλ‘μ΄ κ²°κ³Ό μμ±
public class Main {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
combinedFuture.thenAccept(System.out::println);
}
}
- allOf : μ¬λ¬ κ°μ CompletableFutureκ° λͺ¨λ μλ£λ λκΉμ§ κΈ°λ€λ Έλ€κ° λͺ¨λ μμ μ΄ μλ£λλ©΄ μλ‘μ΄ CompletableFuture λ°ν
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
// λͺ¨λ CompletableFutureκ° μλ£λ λκΉμ§ κΈ°λ€λ¦° νμ μ€ν
allOfFuture.get();
System.out.println("All futures completed");
}
}
- anyOf : μ¬λ¬ κ°μ CompletableFuture μ€μμ νλλΌλ μλ£λ λκΉμ§ κΈ°λ€λ¦° νμ ν΄λΉ μμ μ κ²°κ³Ό λ°ν
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
// κ°μ₯ λ¨Όμ μλ£λ CompletableFutureμ κ²°κ³Ό μΆλ ₯
System.out.println(anyOfFuture.get());
}
}
CompletableFutureμ non-blockingκ³Ό blocking
CompletableFutureμ μ₯μ μ λ€μν taskλ₯Ό blockingνμ§ μκ³ μ‘°ν©ν μ μλ€.
μ‘°ν© μΈμλ supplyAsync(), thenApply(), thenCompose() λ±μ ν΅ν΄μ non-blockingμΌλ‘ μννλ κ²μ νμΈν μ μλ€.
κ·Έλ λ€λ©΄ blockingμ μΈμ λ°μνλ κ²μΌκΉ?
κ²°λ‘ λΆν° λ§νλ©΄,
- get()
- join()
λ±μ λ©μλλ₯Ό μνν λμ΄λ€.
get(), join() λ©μλλ CompletableFutureκ° μλ£λ λκΉμ§ νΈμΆν μ€λ λκ° λΈλ‘νΉλμ΄ μμ μ΄ μλ£λκΈ°λ₯Ό κΈ°λ€λ¦°λ€.
CompletableFuture - 3λΆ μμ
μλμ κ°μ μ½λλ₯Ό λλ €λ³΄λ 3λΆ κ°λ μμλλ€.
@RequiredArgsConstructor
@Service
@Slf4j
public class ApiScheduler {
private final AreaRepository areaRepository;
private final CityDataRepository cityDataRepository;
@Value("${seoul.open.api.url}")
private StringBuilder url;
@Transactional
@Scheduled(cron = "* * * * * *")
public void call() {
List<Area> areas = areaRepository.findAll();
List<CompletableFuture<CityData>> futures = areas.stream()
.map(this::fetchCityDataAsync)
.collect(Collectors.toList());
List<CityData> cityDataList = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
cityDataRepository.deleteAll();
cityDataRepository.saveAll(cityDataList);
}
private CompletableFuture<CityData> fetchCityDataAsync(Area area) {
return CompletableFuture.supplyAsync(() -> {
try {
log.info("areaId: {} areaName: {}", area.getAreaId(), area.getAreaName());
String apiUrl = url + ("/" + urlEncoding(area.getAreaName()));
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(apiUrl);
return parseCityData(document);
} catch (SAXException | IOException | ParserConfigurationException e) {
log.error("error fetching citydata for areaname {}", area.getAreaName(), e);
return null;
}
});
}
private CityData parseCityData(Document document) {
return CityData cityData = CityData.builder()
.areaName(getElement(documentInfo, "AREA_NM"))
.areaCongestionLevel(getElement(documentInfo, "AREA_CONGEST_LVL"))
.areaCongestionMessage(getElement(documentInfo, "AREA_CONGEST_MSG"))
.pplUpdateTime(getElement(documentInfo, "PPLTN_TIME"))
.forecastPopulation(getElement(documentInfo, "FCST_PPLTN"))
.forecastCongestionLevel(getElement(documentInfo, "FCST_CONGEST_LVL"))
.temperature(getElement(documentInfo, "TEMP"))
.maxTemperature(getElement(documentInfo, "MAX_TEMP"))
.minTemperature(getElement(documentInfo, "MIN_TEMP"))
.pm25Index(getElement(documentInfo, "PM25_INDEX"))
.pm10Index(getElement(documentInfo, "PM10_INDEX"))
.pcpMsg(getElement(documentInfo, "PCP_MSG"))
.weatherTime(getElement(documentInfo,"WEATHER_TIME"))
.culturalEventName(getElement(documentInfo, "EVENT_NM"))
.culturalEventPeriod(getElement(documentInfo, "EVENT_PERIOD"))
.culturalEventPlace(getElement(documentInfo, "EVENT_PLACE"))
.culturalEventUrl(getElement(documentInfo, "URL"))
.build();
}
private String getElementText(Document document, String tag) {
// return document.getElementsByTagName(tag).item(0).getTextContent();
// Document κ°μ²΄μμ νκ·Έ μ΄λ¦μ ν΄λΉνλ μμ κ°μ Έμ€κΈ°
NodeList nodeList = document.getElementsByTagName(tag);
// κ°μ Έμ¨ μμκ° λΉμ΄ μλμ§ νμΈ
if (nodeList.getLength() > 0) {
// 첫 λ²μ§Έλ‘ λ°κ²¬λ μμμ ν
μ€νΈ λ΄μ©μ λ°ν
return nodeList.item(0).getTextContent();
} else {
// ν΄λΉ νκ·Έκ° μμ κ²½μ°
return "NO TAG";
}
}
}
CompletableFuture & μν°ν° λΆλ₯νκΈ° - 60~80μ΄ μμ
λ μ¨, μΈκ΅¬, λ¬Έννμ¬ μν°ν°λ₯Ό κ°κ° λΆλ₯νκ³ , νμν λ°μ΄ν°λ€μ κ° μν°ν° νλλ‘ μμ±νλ€.
μ€νμμΌλ³΄λ 60~80μ΄ μ λ μμλμλ€ !
π
μμ§ν 60~80μ΄ κ°λ μμλλ κ²λ λ§μ΄ 걸리λ κ²μ΄λΌ μκ°λλ€.
7-8λΆ μμλλ κ²μ κ·Έλλ 1λΆλλ‘ μ€μμΌλ λΏλ―νλ€λ§....
μ½λκ° ν¨μ¬ κΈΈμ΄μ‘κ³ , μ€λ³΅λλ λ΄μ©λ μμ΄ μ½λ μ체λ‘λ μ© λ§μμ λ€μ§ μλλ€.
WebClientλ‘ APIλ₯Ό νΈμΆνμ¬ μ²λ¦¬νλ λ°©λ² λ± λ€λ₯Έ ν΄κ²°μ±
μ μΆνμ μ μ©μμΌ μ’λ μμλ΄μΌκ² λ€..π
μ°Έκ³ μλ£
https://11st-tech.github.io/2024/01/04/completablefuture/#%EB%B3%91%EB%A0%AC%EC%B2%98%EB%A6%AC
https://mangkyu.tistory.com/263
https://www.baeldung.com/java-completablefuture
https://www.baeldung.com/java-completablefuture-non-blocking
'Java' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Java] μ§λ ¬ν Serializable (0) | 2025.03.07 |
---|---|
[Java] μ λ€λ¦ (0) | 2025.03.05 |
[Java κ³ κΈνΈ] μ€λ λ μμ±κ³Ό μ€ν (0) | 2024.09.30 |