Динамические прокси и RPC

Java
Динамические прокси и RPC

предисловие

С недавним вниманиемcimКоличество людей в проекте увеличивается, что приводит к увеличению вопросов и багов, а в процессе исправления проблем чистота кода неизбежно всплывет вновь.

Глядя на что-то, написанное год или два назад, я всегда задаюсь вопросом, действительно ли это было сделано моими собственными руками? В некоторых местах я не выдержал и начал долгий путь реконструкции.

До и после сравнения

Краткое введение, прежде чем мы начнемcimЭтот проект, следующая его архитектурная схема:

Проще говоря, это система обмена мгновенными сообщениями, которая в основном состоит из следующих частей:

  • IM-serverЕстественно, это сервер, который используется для поддержания длительного соединения с клиентом.
  • IM-clientКлиент можно просто рассматривать как клиентский инструмент, аналогичный QQ; конечно, функции, конечно, не так богаты, и предоставляют только некоторые простые функции отправки и получения сообщений.
  • RouteСлужба маршрутизации в основном используется для аутентификации клиентов, пересылки сообщений и т. д. Она предоставляет некоторые http-интерфейсы, которые можно использовать для просмотра состояния системы, онлайн-номера и других функций.

Конечно, сервер и маршрутизацию можно масштабировать по горизонтали.


Это блок-схема отправки сообщений в предположении, что два сервера A, B и служба маршрутизации теперь развернуты; гдеClientAиClientBПоддерживайте долгосрочные соединения с серверами A и B соответственно.

когдаClientAВ направленииClientBОтправитьhello world, весь поток сообщений показан на рисунке:

  1. пройти первымhttpотправить сообщениеRouteСлужить.
  2. Служба маршрутизации узнаетClientBподключен кServerBна; потом черезhttpотправить сообщениеServerB.
  3. наконец-то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Ощущения от таких сторонних фреймворков совершенно другие.

Весь исходный код для этой статьи:

GitHub.com/crossover J я…

Ваши лайки и репост - лучшая поддержка для меня