1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/liuyueyi-quick-fix

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Quick-Fix

Builder mvn-repository Average time to resolve an issue Percentage of issues still open

I. Описание фона

case1: Программа содержит ошибку

В нашей реальной работе, когда мы сталкиваемся с обратной связью от других людей о том, что код работает неправильно, как нам убедиться, что возвращаемые данные неверны?

После того как приложение работает в течение некоторого времени, наша первая реакция — убедиться, можем ли мы воспроизвести проблему? Если мы можем воспроизвести её, то правильно ли мы вызываем метод? Если мы уверены, что вызов метода правильный, то проблема должна быть в параметрах запроса!!! Если параметры запроса всё ещё не являются проблемой, то, чёрт возьми, возможно, действительно есть ошибка, и что нам тогда делать?

Далее, обычный подход заключается в том, чтобы воспроизвести ситуацию в тестовой среде. Если мы можем это сделать, то мы запускаем отладку (или удалённую отладку), строка за строкой, и мы верим, что скоро сможем решить проблему;

Но самое страшное — это «но», тестовая среда не может воспроизвести проблему, а проблема возникает только в рабочей среде, так что же нам делать?

case2: Проблемы с кэшированием данных

Другой сценарий заключается в том, что для повышения производительности службы кэширование широко используется между различными системами; если есть кэширование, то могут возникнуть проблемы с несогласованностью кэша. Если кэш использует внешние сервисы, такие как Redis или Memcache, то запрос и исправление данных кэша относительно просты; однако, если мы используем память в качестве кэша данных, например, HashMap или Guava, то как мы можем работать с данными в этой памяти? Как мы можем изменить данные в этой памяти?

3. Заключение

Из двух сценариев, описанных выше, можно выделить две основные проблемы:

  • Как узнать результат выполнения определённого метода службы в рабочем приложении?
  • Как узнать результаты определённых данных в памяти рабочего приложения?

II. Разработка решения

Что нам нужно сделать, чтобы решить две проблемы, описанные выше?

1. Проектирование

Как получить доступ к методам и данным приложения? Первое, что приходит на ум, — это рефлексия. Нетрудно выполнить определённый метод экземпляра или получить значение свойства экземпляра с помощью рефлексии, но трудно сделать это ненавязчиво, обеспечить связь с внешним миром и сделать его универсальным.

Прежде всего, нам нужно внедрить EndPoint для реализации связи с внешним миром. Это является основным условием для начала работы. EndPoint компонента Fixer отвечает за приём внешних запросов и пересылку их внутреннему анализатору для выполнения доступа к внутренним службам приложения и вывода результатов внешнему пользователю.

IMAGE

На приведённом выше рисунке показана структура проектирования EndPoint. Поскольку современные Java-приложения редко запускаются напрямую в виде jar-файлов, более распространённым способом является запуск служб в других контейнерах, таких как Tomcat, Spring и т.д. Различные контейнеры предоставляют разные способы предоставления услуг. Как мы можем обеспечить элегантную поддержку в различных контейнерах?

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

IMAGE

2. Технология

Исходя из структуры проектирования, давайте найдём ключевые моменты реализации этого проекта.

a. Определение местоположения службы

Обычно, как определить местоположение требуемого метода службы для выполнения на основе переданных параметров запроса? Службы, предоставляемые приложением, обычно делятся на два типа:

  • Предоставление услуг в форме экземпляров
    • Например, в Spring сервисы представлены в виде Bean. Мы можем использовать Spring ApplicationContext для получения соответствующего bean.
    • Для этого типа сервисов требуется, чтобы приложение само по себе содержало все сервисы, и мы можем определить местонахождение конкретного сервиса через этот ServiceHolder.
  • Один класс соответствует одной службе
    • Этот тип часто представляет собой статический класс или синглтон, который различается на уровне ClassLoader.
    • Поэтому мы можем напрямую загрузить соответствующий класс через ClassLoader.

Наша основная цель должна быть сосредоточена на первом методе. Получение ServiceHolder для разных способов применения неодинаково, и требовать от нас поддержки всех вариантов непрактично. Поэтому нам нужен механизм, позволяющий пользователям выбирать конкретный метод сервиса на основе ServiceHolder в их приложении.

Это может быть достигнуто с помощью механизма SPI.

b. Поддержка EndPoint

Обеспечение взаимодействия с внешним миром, наиболее распространённым решением является предоставление HTTP-интерфейса для приёма внешних запросов. А как насчёт не-web сервисов? Мы также можем открыть сокет для TCP-коммуникации. Тогда возникает вопрос:

  • Для веб-сервисов
    • Должны ли мы просто добавить новую конечную точку к существующему веб-сервису и добавить контроль доступа?
    • Или мы должны предоставить услугу на другом порту?
  • Для не-веб-сервисов
    • Мы должны открыть новый порт для предоставления услуги.

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

  • Как повторно использовать существующие веб-сервисы?
  • Без веб-сервиса, как мы поддерживаем веб-сервис?
  • Как поддерживать конфигурацию привязки порта?
  • Когда в проекте представлено несколько способов поддержки EndPoint, как гарантировать, что активен только один из них?

При конкретной реализации будут использоваться следующие механизмы:

  • Введение приоритета
  • Реализация пользовательских расширений с помощью SPI
  • Анализ параметров JVM для получения соответствующей конфигурации

III. Связанные статьи

От проектирования до реализации, следующие статьи подробно описывают:

Техническая документация

IV. Использование

1. Управление зависимостями

Сначала добавьте репозиторий, есть два способа: один — это использование версии release на GitHub, преимущество заключается в стабильности; убедитесь, что проблема с обновлением решена;

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

Другой способ — использовать мой личный репозиторий

<repositories>
    <repository>
        <id>yihui-maven-repo</id>
        <url>https://raw.githubusercontent.com/liuyueyi/maven-repository/master/repository</url>
    </repository>
</repositories>

2. Импорт пакетов зависимостей

В зависимости от фактического сценария приложения импортируйте соответствующий пакет зависимостей,

a. Чистое Jar-приложение

<dependency>
    <groupId>com.git.hui.fix</groupId>
    <artifactId>fix-core</artifactId>
    <version>1.4.2</version>
</dependency>

Примечание:

  • fix-core имеет встроенный http-сервер, который по умолчанию привязан к порту 9999, вы можете переопределить его с помощью параметра jvm -Dquick.fix.port;
  • необходимо вручную выполнить FixEngine.instance(); для инициализации при входе в приложение;
  • поскольку fix-core предоставляет только ServerLoader для статических классов, вам нужно самостоятельно реализовать загрузку экземпляров.

Используйте следующим образом:

curl -X POST -H "Content-Type:application/json" http://127.0.0.1:9999/fixer/call -d '{"service": "CalculateServer", "method": "getCache", "params": ["init"], "type":"static"}'

Пример demo: jar-example (examples/jar-example)

b. Чистое Spring-приложение

Если у меня чистое Spring-приложение и я не использую SpringMVC, я могу импортировать

<dependency>
    <groupId>com.git.hui.fix</groupId>
    <artifactId>spring-fixer</artifactId>
    <version>1.4.2</version>
</dependency>

Примечание: spring-fixer предоставляет способ доступа к bean-компонентам в контейнере Spring, поэтому, помимо получения статического класса по умолчанию, вы также можете получить доступ к bean-компоненту;

  • используйте http-сервер по умолчанию с портом 9999 и переопределите его с помощью jvm-параметра -Dquick.fix.port ;
  • в отличие от предыдущего, нет необходимости вручную вызывать FixEngine.instance();
  • spring-fixer внутренне предоставляет ServerLoader для bean-компонентов, к которым можно получить прямой доступ через beanName или полное имя класса компонента.

Используйте следующим образом:

# Выполнение метода определенного bean
curl -X POST -H "Content-Type:application/json" http://127.0.0.1:8080/inject-fixer-endpoint/call -d '{"service": "demoBean", "method": "randName"}'
# Просмотр значения свойства bean
curl -X POST -H "Content-Type:application/json" http://127.0.0.1:8080/inject-fixer-endpoint/call -d '{"service": "demoBean", "field": "name"}'
# Выполнение метода свойства bean
curl -X POST -H "Content-Type:application/json" http://127.0.0.1:8080/inject-fixer-endpoint/call -d '{"service": "demoBean", "field": "values", "method":"add", "params": ["autoInsertByQuickFixer!"]}'

# Тестирование вызова метода статического члена статического класса
curl -X POST -H "Content-Type:application/json" http://127.0.0.1:9999/fixer/call -d '{"service": "com.git.hui.fix.example.spring.server.StaticBean", "method": "getCache", "params": ["init"], "type":"static"}'

# Пример использования одноэлементного класса
curl -X POST -H "Content-Type:application/json" http://127.0.0.1:8080/inject-fixer-endpoint/call -d '{"service": "SingletonBean", "method": "getInstance", "secondMethod": "sayHello", "secondParams": ["init"], "type":"static"}'

Пример демо: spring-example (examples/spring-example)

c. SpringMVC-приложение

Если это SpringMVC-приложение, вы можете импортировать

<dependency>
    <groupId>com.git.hui.fix</groupId>
    <artifactId>spring-mvc-fixer</artifactId>
    <version>1.4.2</version>
</dependency>

Использование: используйте http-сервис, предоставляемый самим mvc, доступ осуществляется по пути /inject-fixer-endpoint/call, поэтому необходима проверка безопасности.

Используйте так же, как и предыдущие классы. Пример демо: spring-mvc-example (examples/spring-mvc-example)

d. Приложение SpringCloud

Если это приложение SpringCloud и вы включили мониторинг приложений actuator, вы можете импортировать

<dependency>
    <groupId>com.git.hui.fix</groupId>
    <artifactId>spring-cloud-fixer</artifactId>
    <version>1.4.2</version>
</dependency>

Использование: интегрируйте FixEndPoint с Actuator в SpringCloud, поэтому при фактическом использовании вам необходимо включить его в конфигурации и установить параметр management.endpoints.web.exposure.include. Доступ осуществляется по пути: /actuator/inject-fixer-endpoint/call, где путь actuator совпадает с путем конфигурации мониторинга приложений.

Используйте таким же образом, как и в предыдущих классах. Пример демо: spring-cloud-example (examples/spring-cloud-example)

V. Конец

Информация о версии

v1.1

  • Завершена базовая функциональность quick-fix, реализован доступ к сервисам и данным внутри приложения;
  • Интегрирован http-сервер на основе сокетов, используемый в качестве стандартного канала взаимодействия между приложением и внешним миром;
  • Поддержка прямого использования в Spring Jar-приложении;
  • Поддержка Spring MVC-приложений;
  • Поддержка Spring Cloud-приложений.

v1.2 Поддержка указания приоритета ServerLoader

  • Используйте gson вместо fastjson, чтобы решить проблему некорректного формата JSON из-за отсутствия двойных кавычек для ключей при сериализации.

Версия 1.3

  • Добавлена поддержка рефлексивного вызова синглтона; поддерживается двухуровневый цепной вызов методов.

Версия 1.4

  • Задача №4 добавлена поддержка расширения анализа параметров.
    • По умолчанию предоставляются восемь основных типов данных, BigInteger, BigDecimal, Class, Enum, преобразование параметров для объектов POJO в формате JSON.
    • С помощью JDK SPI загружается пользовательский анализатор параметров, наследующий IArgParser.
  • Задача №5 решена проблема поддержки передачи параметров как null.
  • В проекте spring-mvc-example добавлен пример demo для передачи параметров через перечисления.

Версия 1.4.1

  • Исправлена проблема несоответствия регистра заголовка запроса в HttpMessageParser в разных средах.

Версия 1.4.2

  • Добавлено логирование точек входа.

Прочее

Отказаться от использования одного компьютера, приветствуется start или добавление друзей для поддержки.

Заявление

Лучше не верить книге, а полагаться на то, что уже написано. Поскольку мои личные способности ограничены, возможно, есть упущения и ошибки. Если вы обнаружите ошибку или у вас есть лучшее предложение, пожалуйста, критикуйте и исправляйте. Буду благодарен.

  • Адрес в Weibo: блог Сяо Хуэй Хуэй.
  • QQ: один Хуэй Хуэй/3302797840; группа общения: 864706093.
  • WeChat: один Хуэй / liuyueyi25.

Сканирование для подписки

Публичный аккаунт и блог.

QrCode

Код вознаграждения

pay

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Доступ к памяти приложения, инструмент для исправления доступа к внутренним данным приложения. Развернуть Свернуть
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/liuyueyi-quick-fix.git
git@api.gitlife.ru:oschina-mirror/liuyueyi-quick-fix.git
oschina-mirror
liuyueyi-quick-fix
liuyueyi-quick-fix
master