предисловие
Глядя на что-то, написанное год или два назад, я всегда задаюсь вопросом, действительно ли это было сделано моими собственными руками? В некоторых местах я не выдержал и начал долгий путь реконструкции.
До и после сравнения
Краткое введение, прежде чем мы начнемcimЭтот проект, следующая его архитектурная схема:
Проще говоря, это система обмена мгновенными сообщениями, которая в основном состоит из следующих частей:
-
IM-serverЕстественно, это сервер, который используется для поддержания длительного соединения с клиентом. -
IM-clientКлиент можно просто рассматривать как клиентский инструмент, аналогичный QQ; конечно, функции, конечно, не так богаты, и предоставляют только некоторые простые функции отправки и получения сообщений. -
RouteСлужба маршрутизации в основном используется для аутентификации клиентов, пересылки сообщений и т. д. Она предоставляет некоторые http-интерфейсы, которые можно использовать для просмотра состояния системы, онлайн-номера и других функций.
Конечно, сервер и маршрутизацию можно масштабировать по горизонтали.
Это блок-схема отправки сообщений в предположении, что два сервера A, B и служба маршрутизации теперь развернуты; гдеClientAиClientBПоддерживайте долгосрочные соединения с серверами A и B соответственно.
когдаClientAВ направленииClientBОтправитьhello world, весь поток сообщений показан на рисунке:
- пройти первым
httpотправить сообщениеRouteСлужить. - Служба маршрутизации узнает
ClientBподключен кServerBна; потом черезhttpотправить сообщениеServerB. - наконец-то
ServerBпередать сообщение сClientBдлинный канал связиpushПродолжайте, пока сообщение успешно отправлено.
Вот я перехватилClientAВ направленииRouteКод для инициации запроса:
okhttpинициировалhttpЗапрос, хотя это может выполнить функцию, но это не элегантно.
Например: Предположим, нам нужно подключиться к интерфейсу Alipay, естественно, нет проблем с отправкой http-запроса сюда, но когда различные отделы внутри Alipay напрямую обращаются к интерфейсу друг друга, исходный http-запрос использовать не следует.
должно быть предоставлено поставщиком услугapiПакет, потребители услуг должны полагаться только на этот пакет для реализации интерфейсных вызовов.
Конечно, в конце концов вы можете использовать http или собственный частный протокол.
Также похоже на то, что мы используемDubboилиSpringCloud, обычно опираясь непосредственно наapipackage, удаленный сервис может вызываться как локальный метод, а основные детали полностью экранированы.Неважно, использует ли он http или другие частные протоколы, и вызывающему абоненту все равно.
Если вы так говорите, то есть ли какой-то внутренний вкус? Разве это не официальное объяснение RPC.
То же самое и здесь,Client,Route,ServerПо сути, все они представляют собой систему, и их интерфейсные вызовы друг к другу тоже должны бытьRPCтолько разумно.
Итак, то, что я реорганизовал, стало таким:
Код намного проще, как вызов нативного метода, и есть несколько преимуществ:
- Основные детали полностью защищены, а бизнес-код и код обслуживания могут быть реализованы лучше.
- Даже если сервис-провайдер модифицирует параметры, это можно быстро обнаружить при компиляции, а вызов по-прежнему совершенно незнающий, так что это тоже повышает риск.
Динамический прокси, который невозможно обойти
Поговорим о том, как это реализовано.
На самом деле, выше«Практическое применение динамических агентов»Также упоминается, что принцип аналогичен.
Для того, чтобы быть невидимым для вызывающего, необходимо создать прокси-объект интерфейса, в котором реализован процесс кодирования, вызова и декодирования.
Соответствующее здесь на самом деле создатьrouteApiПрокси-объект, ключом является этот код:
RouteApi routeApi = new ProxyManager<>(RouteApi.class, routeUrl, okHttpClient).getInstance();
Полный исходный код выглядит следующим образом:
один из нихgetInstance()Функция возвращает объект интерфейса, который необходимо проксировать;ProxyInvocationэто реализацияInvocationHandlerКласс интерфейса, этот набор кода должен использоватьJDKТри оси для реализации динамического прокси.
ПроверятьProxyInvocationИсходный код обнаружит, что когда мы вызываем любой метод прокси-интерфейса, он выполняетinvoke()метод.
иinvoke()Этот метод естественным образом реализует процесс кодирования, удаленного вызова и декодирования, упомянутый на рисунке выше; я думаю, что его легко понять каждому, поскольку он не является предметом данного обсуждения, я не буду вводить его слишком подробно.
Суммировать
На самом деле понять их несложноDubboэтот видRPCОсновной исходный код фреймворка доступен, и общая идея аналогична, за исключением того, что он использует частный протокол, поэтому кодирование и декодирование будут отличаться.
Так что если вы хотите сделать это самиRPCFramework, вы могли бы также попробовать эту идею, когда вы запускаете код, который вы написали сами.RPCизhelloworldЯ чувствую, что я интегрировался с самим собойDubbo,SpringCloudОщущения от таких сторонних фреймворков совершенно другие.
Весь исходный код для этой статьи:
Ваши лайки и репост - лучшая поддержка для меня