Пытаюсь разобраться, могу ли я использовать Spring Reactive (Flux/Mono) вместе с Spring MVC ? Структура микросервисы с использованием Spring MVC + Feign Client, Eureka Server (Netflix OSS), Hystrix, база данных MySQL.
Мой первый микросервис addDistanceClient добавляет данные в базу данных. Вот пример контроллера:
@RequestMapping("/")
@RestController
public class RemoteMvcController {
@Autowired
EmployeeService service;
@GetMapping(path = "/show")
public List<EmployeeEntity> getAllEmployeesList() {
return service.getAllEmployees();
}
}
Здесь я могу использовать Mono/Flux, я думаю не будет никаких проблем.
Мой второй микросервис showDistanceClient - он не связан напрямую с базой данных. У него есть метод, который вызывает метод (который описан выше) у первого микросервиса для получения данных из базы данных. Здесь используется Feign Client.
Контроллер второго микросервиса:
@Controller
@RequestMapping("/")
public class EmployeeMvcController {
private ServiceFeignClient serviceFeignClient;
@RequestMapping(path = "/getAllDataFromAddService")
public String getData2(Model model) {
List<EmployeeEntity> list = ServiceFeignClient.FeignHolder.create().getAllEmployeesList();
model.addAttribute("employees", list);
return "resultlist-employees";
}
}
и сам ServiceFeignClient, с помощью которого мы вызываем метод на первом микросервисе, выглядит следующий образом:
@FeignClient(name = "add-client", url = "http://localhost:8081/", fallback = Fallback.class)
public interface ServiceFeignClient {
class FeignHolder {
public static ServiceFeignClient create() {
return HystrixFeign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(ServiceFeignClient.class, "http://localhost:8081/", new FallbackFactory<ServiceFeignClient>() {
@Override
public ServiceFeignClient create(Throwable throwable) {
return new ServiceFeignClient() {
@Override
public List<EmployeeEntity> getAllEmployeesList() {
System.out.println(throwable.getMessage());
return null;
}
};
}
});
}
}
@RequestLine("GET /show")
List<EmployeeEntity> getAllEmployeesList();
}
Он работает исправно сейчас. Т.е. если оба микросервиса в порядке, я получаю данные из базы данных. Если первый микросервис умер, то когда я вызываю метод чтобы получить данные из базы данных через первый микросервис, я получаю страницу, на которой крутится спиннер и текст о том, что сервис недоступен, попробуйте позже. Все отлично.
Моя цель: Сделать так, используя Spring Reactive (не уверен что мне это поможет, но думаю я мыслю в правильном направлении) сделать так, чтобы сообщение что сервис в даный момент недоступен и крутящийся спиннер на втором микросервисе автоматически пропали и отобразились данные из базы данных, как только первый микросервис снова оживет (без повторной отправки запроса, т.е. без перезагрузки страницы). Смогу ли я это сделать через Spring WebFlux ? Я знаю что через Spring WebFlux используется поток, который сам нас уведомит, если в нем появятся данные, нам не нужно здесь делать повторную отправку запроса.
Я начал думать над этим и не могу понять, как мне это сделать:
1) используя Spring reactive В таком случае мне надо во втором микросервисе sgowDistanceClient внедрить Flux/Mono в MVC модель, которая возвращает html. Я не понимаю как. Я знаю как это сделать с REST.
2) Если первый пункт неверный, может мне надо использовать WebSocket для этого ? Если это так, поделитесь пожалуйста ползными ссылками с примерами. Буду очень благодарен.
Действительно эта тема мне очень интересна и я хочу разобраться в ней. Я буду вам очень благодарен за вашу помощь. Спасибо всем!
ИЗМЕНЕНО:
Я переделал оба контроллера под REST + WebFlux. Все работает для меня.
Первый сервис addDistanceClient и его контроллер:
@RestController
@RequestMapping("/")
public class BucketController {
@Autowired
private BucketRepository bucketRepository;
// Get all Bucket from the database (every 1 second you will receive 1 record from the DB)
@GetMapping(value = "/stream/buckets/delay", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Bucket> streamAllBucketsDelay() {
return bucketRepository.findAll().delayElements(Duration.ofSeconds(5));
}
}
Он достает из базы данных все записи с интервалом в 5 секунд каждую запись. Интервал я добавил для примера чтобы протестировать.
Второй сервис showDistanceClient и его контроллер. Здесь я использовал WebClient вместо Feign Client.
@RestController
@RequestMapping("/")
public class UserController {
@Autowired
private WebClient webClient;
@Autowired
private WebClientService webClientService;
// Using WebClient
@GetMapping(value = "/getDataByWebClient",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Bucket> getDataByWebClient() {
return webClientService.getDataByWebClient();
}
}
и его Сервис слой (WebClientService):
@Service
public class WebClientService {
private static final String API_MIME_TYPE = "application/json";
private static final String API_BASE_URL = "http://localhost:8081";
private static final String USER_AGENT = "User Service";
private static final Logger logger = LoggerFactory.getLogger(WebClientService.class);
private WebClient webClient;
public WebClientService() {
this.webClient = WebClient.builder()
.baseUrl(API_BASE_URL)
.defaultHeader(HttpHeaders.CONTENT_TYPE, API_MIME_TYPE)
.defaultHeader(HttpHeaders.USER_AGENT, USER_AGENT)
.build();
}
public Flux<Bucket> getDataByWebClient() {
return webClient.get()
.uri("/stream/buckets/delay")
.exchange()
.flatMapMany(clientResponse -> clientResponse.bodyToFlux(Bucket.class));
}
}
Теперь все работает в реактивной среде. Отлично.
Но моя проблема осталась нерешенной.
Моя цель: все работает, все хорошо, и если вдруг я вызвал на втором сервисе метод который при помощи WebClient вызвал первы сервис чтобы получить данные, и в этот момент мой первый сервис умер, я получил сообщение что сервис временно недоступен и потом мой первый сервис ожил и мой запрос на получение данных продолжилс и я получил все данные и вместо сообщения о том, что сервис временно недоступен я получу все даннык (важно: без перезагрузки страницы).
Как мне добиться этого ?
Вопрос закрыт. Как оказалось MVC нельзя подружить с WebFlux (точнее можно, но мне нужно возвращать не модель, а реальный json). Также тот функционал нельзя осуществить: если первый сервис умирает то коннекшен теряется. Невозможно продолжать его держать. Тут скорее помогут паттерн Retry - но его сложно внедрить в Реактивную среду без свистопляски. Всем спасибо.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Сейчас учу php,дошел до изучения куки,но функция setcookie не работает ни в какую и вызывает ошибкуВот собственно код(даже скопи-пастил код из офф
Помогите, делаю поиск по БД, но не могу понять как правильно сформировать запросЕсть таблица, в которой 10 столбцов, Я хочу что бы через форму...
Пытаюсь загрузить видео на Facebook через Graph-Api, там указано: