Остальная конечная точка ничего не делает, а вызывает две другие внешние службы, над которыми я не могу контролировать. Сетевые вызовы являются дорогостоящими (обработка каждого стороннего вызова занимает более 5 секунд).
Данные, возвращаемые обоими сторонними сервисами, также не часто меняются.
Поэтому я подумываю об использовании кэша. То есть, используя SpringBoot, Spring кэш и Caffeine.
Из-за производственных требований я также хотел бы добавить в кеш возможность наблюдения с помощью микрометра. Возможность видеть промахи в кеше. попадание в кэш является обязательным.
Чтобы добиться вышеуказанного, я попытался написать следующий код:
Код: Выделить всё
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-cache
com.github.ben-manes.caffeine
caffeine
org.springframework.boot
spring-boot-starter-actuator
io.opentelemetry
opentelemetry-exporter-otlp
io.micrometer
micrometer-tracing-bridge-otel
io.micrometer
micrometer-registry-otlp
Код: Выделить всё
package controller;
import com.ivoronline.model.MedicalReportDto;
import com.ivoronline.model.PatientInfoDto;
import com.ivoronline.service.InfoService;
import com.ivoronline.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
PersonService personService;
@Autowired
InfoService infoService;
@GetMapping("/getAll")
public String getAll(@RequestParam String name) {
PatientInfoDto person = personService.getPatientInfo(name);
MedicalReportDto medical = infoService.getLatestReport(name);
return person.toString() + medical.toString();
}
}
Код: Выделить всё
package service;
import com.ivoronline.model.MedicalReportDto;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class InfoService {
private final RestClient restClient;
public InfoService(RestClient.Builder restClientBuilder) {
this.restClient = restClientBuilder.build();
}
@Cacheable(cacheNames = "ReportInfo")
public MedicalReportDto getLatestReport(String PatientId) {
System.out.println("Fetching Latest Report of Patient (but please apply cache here to see only one call per ID) : {}" + PatientId);
ResponseEntity response = this.restClient.get()
.uri("http://localhost:8083/report/getreport/" + PatientId)
.retrieve()
.toEntity(String.class);
System.out.println(response.getBody());
return new MedicalReportDto(response.getBody());
}
}
Код: Выделить всё
package service;
import com.ivoronline.model.PatientInfoDto;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import java.util.Map;
@Service
public class PersonService {
private final RestClient restClient;
public PersonService(RestClient.Builder restClientBuilder) {
this.restClient = restClientBuilder.build();
}
@Cacheable(cacheNames = "PatientInfo")
public PatientInfoDto getPatientInfo(String BedDeptNum) {
System.out.println("Fetching Patient Info (but please apply cache here to see only one call per ID): {}" + BedDeptNum);
ResponseEntity response = this.restClient.post()
.uri("http://localhost:8888/patient/")
.body(Map.of("BedDeptNum", BedDeptNum))
.retrieve()
.toEntity(String.class);
System.out.println(response.getBody());
return new PatientInfoDto(response.getBody());
}
}
За каждым тайником нужно следить.
Код: Выделить всё
mport com.github.benmanes.caffeine.cache.Caffeine;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.cache.CaffeineCacheMetrics;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager(MeterRegistry registry) {
// How to construct caffeine manager for each of the two below caches, with observability?
return manager;
}
private CaffeineCache reportCache() {
return new CaffeineCache("ReportInfo", Caffeine.newBuilder()
.expireAfterWrite(, TimeUnit.MINUTES) // some custom time
.maximumSize() // some custom size
.recordStats()
.build());
}
private CaffeineCache patientCache() {
return new CaffeineCache("PatientInfo", Caffeine.newBuilder()
.expireAfterWrite(, TimeUnit.MINUTES) // some other custom time
.maximumSize() // some other custom size
.recordStats()
.build());
}
}
Что поместить в файл Configuration.java так:
- Оба кеша имеют свои собственные метрики
- каждый из кешей имеет свою собственную конфигурацию
Подробнее здесь: https://stackoverflow.com/questions/793 ... ches-in-on
Мобильная версия