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

OSCHINA-MIRROR/handyun-dactor

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

DActor

Введение

DActor — это фреймворк, основанный на идее сопрограмм. Он позволяет одновременно работать с синхронным и асинхронным кодом, упрощая разработку асинхронного кода. DActor сочетает в себе преимущества асинхронного программирования (высокая степень параллелизма, отсутствие блокировок) и синхронного (простота и удобство сопровождения).

Основные цели DActor:

  • максимально снизить блокировки;
  • повысить производительность одного потока;
  • эффективно уменьшить количество потоков.

Адрес проекта

GitHub: https://github.com/allon2/dactor GitEE: https://gitee.com/handyun/dactor

Документация

  • Обновление журнала: ChangeLog.
  • Описание аннотаций: «Описание конфигурации аннотаций».
  • Описание конфигурации представлений: «Описание конфигурации представлений».
  • SpringBoot Yml конфигурация: «Yml конфигурация».
  • XML конфигурация: «XML конфигурация».
  • Часто используемые классы: «Часто используемые классы».
  • Конфигурация и API: «Конфигурация и API».
  • Дополнительная документация: WIKI.

QQ группа для общения 783580303

Интеграция с системами Dpress — многодоменный блог на основе Dactor.

Текущие модели разработки

  1. Синхронное программирование. Все шаги выполняются в одном главном потоке. Вызов метода приводит к ожиданию ответа. Если есть операции с базой данных, TCP или HTTP-связь, то из-за блокировок поток не может быть освобождён вовремя. Чтобы решить эту проблему, в синхронных транзакциях используется концепция пула потоков для повышения пропускной способности системы.
  2. Асинхронное программирование. Шаги могут выполняться в разных потоках. Вызов метода не требует ожидания ответа. Примером является NodeJs. В настоящее время асинхронные фреймворки сложны, а общим решением являются CallBack и Promise/Deferred.

Дизайн

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

  • Запрос упаковывается в сообщение и помещается в очередь сообщений.
  • Находятся подходящие шаги для обработки сообщения.
  • Процесс повторяется до тех пор, пока все доступные шаги не будут выполнены. Для синхронных транзакций обработка завершается после помещения запроса в очередь. Для асинхронных транзакций запрос помещается в очередь только после завершения обратного вызова. Обе ситуации обрабатываются одинаково. Благодаря асинхронному подходу, можно избежать блокировок и увеличить пропускную способность без значительного увеличения количества потоков. Также снижается риск перегрузки при внезапном увеличении трафика. Очередь сообщений основана на высокопроизводительной очереди RingBuffer от Disruptor. Фреймворк основан на модели Actor и параллелизме сопрограмм.

Особенности

  • Интеграция Netty.
  • Интеграция HttpClient.
  • Поддержка многослойной структуры родитель-потомок.
  • Поддержка цепочки ответственности.
  • J2EE поддерживает JSON, CSV, PDF, XML, HTML.
  • J2EE поддерживает вывод данных в потоковом режиме, динамическую загрузку файлов, вывод динамических изображений, переход по ссылкам и динамический вывод в соответствии с конфигурацией.
  • Поддерживает Spring Boot и Spring.

Требования к среде

  • JDK 1.8.
  • Spring Framework 5.2.4.RELEASE + или Spring Boot 2.2.7.RELEASE +.
  • Servlet 3.0+ (для использования асинхронных функций Servlet).

Примечание

Рекомендуется избегать использования ThreadLocal, так как логика запросов выполняется в разных потоках.

Начало работы

Пример представляет собой программу J2EE, которую можно запустить сразу после загрузки. Она содержит несколько примеров. По умолчанию используется .do для выполнения транзакций, но если это .json, будет возвращён JSON. После запуска введите http://localhost:8080/example/randomTxt2.json в браузере. Будет выведена строка в формате JSON. randomTxt2 имеет одноуровневую структуру родитель-потомок, randomTxt1 — двухуровневую. chaintest1 использует только цепочку ответственности, chaintest2 — цепочку и одноуровневую структуру. exceptionTest демонстрирует обработку ошибок в рамках транзакции. randomTxt3 — пример с использованием Actor BeanId. httptest показывает, как использовать HttpClient для асинхронного доступа к сайту Baidu. Доступ к URL: http://localhost:8080/example/httptest.do. http://localhost:8080/example/np.randomTxt2.json — пример использования пространства имён. Конфигурация находится в conf/namespace.xml. После запуска результаты внутренних вызовов отображаются в консоли.

Зависимости Maven

<dependency>
    <groupId>cn.ymotel</groupId>
    <artifactId>dactor</artifactId>
    <version>1.1.2</version>
</dependency>

Gradle зависимости

compile group: 'cn.ymotel', name: 'dactor', version:'1.1.2'

Простое объяснение кода Процесс выполнения включает цепочку, grandfather, parent и Selft. Шаги вызываются последовательно в цепочке ответственности, логике grandfather, логике parent и собственной логике. Цепочка, grandfather и parent могут быть пустыми и не заданы. В логике grandfather и parent необходимо иметь хотя бы один шаг placeholderActor для вызова дочерней логики. Перевод текста на русский язык:

``` condtion может быть пустым, пустой строкой или выражением ognl placeholderActor используется для временного хранения текущей среды и вызова дочерней транзакции. После завершения выполнения дочерней транзакции среда восстанавливается и выполнение продолжается Если в Step не найден toBeanIdActor, то будет напрямую вызван метод endBeanId, что означает завершение собственной транзакции Информация о запросе и потоке транзакции сохраняется в Message При указании handleException=false или использовании значения по умолчанию, результат возвращается родительскому элементу для выполнения. Если родительский элемент также не обрабатывает исключение, то результат возвращается на уровень выше Как правило, хотя бы один actor должен иметь handleException=true Запуск фреймворка для приёма и выполнения запросов # **Синхронная и асинхронная запись** ## Синхронная запись ``` public class BeginActor implements Actor {
/* (non-Javadoc)
 * @see com.ymotel.util.actor.Actor#HandleMessage(com.ymotel.util.actor.Message)
 */
@Override
public Object HandleMessage(Message message) throws Exception {
    return message;

}

}

Наследуйте интерфейс Actor и в методе HandlerMessage возвращайте message. Фреймворк определит, является ли возвращаемое значение непустым, и если да, то передаст результат для дальнейшей обработки

## Асинхронная запись
Например, в HttpClientActor в HandlerMessage возвращается null. После получения запроса фреймворк ожидает следующей обработки, освобождает поток, а затем в CallBack метода HttpClient вызывает message.getControlMessage().getMessageDispatcher().sendMessage(message). После этого фреймворк продолжает обработку.
public Object HandleMessage(final Message message) throws Exception {
    Map context = message.getContext();

//
HttpUriRequest request = getHttpBuild(message.getContext()).build();

    if (referer != null) {
        request.addHeader("Referer", referer);
    }


    /**
     * Здесь можно использовать общий сеанс для проведения транзакций, подобных логину
     */
    HttpClientContext tmplocalContext = null;
    if (context.containsKey(HTTPCLIENT_CONTEXT)) {
        tmplocalContext = (HttpClientContext) context.get(HTTPCLIENT_CONTEXT);
    } else {
        tmplocalContext = HttpClientContext.create();
        CookieStore cookieStore = new BasicCookieStore();
        tmplocalContext.setCookieStore(cookieStore);
        context.put(HTTPCLIENT_CONTEXT, tmplocalContext);
    }

    final HttpClientContext localContext = tmplocalContext;

// CookieStore cookieStore = new BasicCookieStore(); // localContext.setCookieStore(cookieStore); if (logger.isInfoEnabled()) { logger.info("HandleMessage(Message) - httpclient----" + request); //$NON-NLS-1$ } // final HttpGet httpget = new HttpGet(uri);

    final String tmpcontent = content;
    final String tmpcharset = charset != null ? charset : (String) context.get(CHARSET);


    httpClientHelper.getHttpclient().execute(request, localContext, new FutureCallback<HttpResponse>() {

        public void completed(final HttpResponse response) {
            try {
                /**
                 * Завершить и своевременно очистить
                 */
                message.getContext().remove(tmpcontent);

                actorHttpClientResponse.handleResponse(response, localContext, tmpcharset, message);

// String responseString=HandleResponse((String)message.getContext().get(CHARSET),response); // message.getContext().put(RESPONSE, responseString); } catch (Exception e) { // TODO Auto-generated catch block if (logger.isErrorEnabled()) { logger.error("$FutureCallback.completed(HttpResponse)", e); //$NON-NLS-1$ } message.setException(e); message.getControlMessage().getMessageDispatcher().sendMessage(message); } // System.out.println(httpget.getRequestLine() + "->" + response.getStatusLine()); }

        public void failed(final Exception ex) {
            if (logger.isErrorEnabled()) {
                logger.error("$FutureCallback<HttpResponse>.failed(Exception)", ex); //$NON-NLS-1$
            }
            message.setException(ex);
            message.getControlMessage().getMessageDispatcher().sendMessage(message);

// System.out.println(httpget.getRequestLine() + "->" + ex); }

        public void cancelled() {
            Exception exception

**Конфигурация**

В XML через Step реализуется переход между внутренними процессами Actor. В конфигурационном файле содержатся конфигурации Actor, chain и global.

Порядок выполнения программы: согласно коду транзакции находится соответствующий Actor, затем выполняется в порядке chain → parent → self. Выполнение chain завершается в placeholder, вызывается parent транзакция для продолжения выполнения. После выполнения parent транзакции вызывается self транзакция. Когда self транзакция завершена, возобновляется выполнение parent транзакции с placeholder. Завершение parent транзакции возобновляет выполнение chain.

Глобальная конфигурация:

<actor:global id="actorglobal"> <actor:param name="beginBeanId" value="beginActor"/> <actor:param name="endBeanId" value="endActor"/> </actor:global>

beginBeanId — это начальный Actor по умолчанию, значение в value соответствует beanName в Spring, программа инициализируется этим значением, и глобальная конфигурация инициализируется для Actor без указания beginBeanId или endBeanId. beginActor и endActor должны наследовать интерфейс Actor.

Конфигурация Actor:

<actor:actor id="actorhttpcore" parent="chainparent" chain="unLoginChain" handleException="true" endBeanId="FinishActor" >

<actor:steps>
    <actor:step xpoint="" ypont="" fromBeanId="beginActor"  conditon="" toBeanId="placeholderActor"/>
     <actor:step xpoint="" ypont="" fromBeanId="beginActor"  conditon="" async="true"  toBeanId="placeholderActor"/>
   <actor:step xpoint="" ypont=""  fromBeanId="placeholderActor" conditon="context._SUFFIX=='json'"  toBeanId="JsonViewResolverActor"/>
    <actor:step xpoint="" ypont=""  fromBeanId="placeholderActor" conditon="exception==null" toBeanId="ViewResolveActor"/>
    <actor:step xpoint="" ypont=""   fromBeanId="placeholderActor" conditon="exception!=null"  toBeanId="ErrorViewResolveActor"/>
</actor:steps>
     <results>
            <result name="success">htmlstream:</result>
     </results>

</actor:actor>

Если handleException не установлен, при возникновении исключения программа считает, что дочерний класс завершил выполнение, и переходит к PlaceHolder в parent. Если установлено значение true, то переход к parent не будет выполнен, и дочерний класс обработает исключение самостоятельно.

parent и chain — это общие транзакции, которые необходимо вызвать перед вызовом конкретной транзакции. Большинство транзакций имеют общие предварительные транзакции и унифицированные последующие транзакции. Установка parent или chain может повысить степень повторного использования кода.

fromBeanId и toBeanId определяют конфигурацию Actor или beanId, реализующий Actor. parent и chain ref должны быть Actor. results могут определять возвращаемое состояние и требуемый viewActor. async определяет, является ли транзакция параллельной, по умолчанию — false, если установлено значение true, контекст будет скопирован, создано новое сообщение, и выполнено без влияния на основной поток.

Цепочка конфигурации:

<actor:chain id="isLoginChain">

      </list>
  </actor:chain>
chain может наглядно отображать порядок вызова Actor. Несколько parent могут быть последовательно и параллельно размещены в chain. Каждый родительский Step должен иметь placeHolderActor для вызова дочернего класса.

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

Пространство имён:

<actor:actors xmlns="http://www.ymotel.cn/schema/dactor" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:actor="http://www.ymotel.cn/schema/dactor" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.ymotel.cn/schema/dactor http://www.ymotel.cn/schema/dactor.xsd" namespace="np"> </actor:actors>

В Actor можно добавить пространство имён, чтобы упростить разработку кода. В Actor настройте namespace=np, тогда идентификатор actor в экземпляре автоматически объединится в np.randomTxt2.

http://localhost:8080/example/np.randomTxt2.json — пример использования пространства имён, соответствующая конфигурация находится в conf/namespace.xml.

**Важные классы и методы**

cn.ymotel.dactor.core.MessageDispatcher — основной интерфейс класса для управления транзакциями. Метод public void startMessage(Message message, ActorTransactionCfg actorcfg, boolean blocked) throws Exception используется для запуска всего процесса, где message должен быть сконструирован перед выполнением, actorcfg можно получить через spring getBean следующим образом:
``` С помощью getBean('randomTxt1') можно получить ActorTransactionCfg. blocked указывает, блокируется ли он, обычно устанавливается в false при первом добавлении транзакции в очередь, указывая, что если очередь заполнена, она напрямую отправляется клиенту для обработки. Значение true обычно используется для внутренних транзакций и должно быть отправлено в очередь для обработки. Метод sendMessage вызывается внутри для того, чтобы повторно поместить обработанное сообщение в очередь и продолжить следующий шаг процесса.

Cn.ymotel.dactor.core.disruptor.MessageRingBufferDispatcher — это класс, реализующий интерфейс MessageDispatcher. При запуске Spring необходимо добавить в конфигурацию следующее:

<bean id="MessageRingBufferDispatcher" class="cn.ymotel.dactor.core.disruptor.MessageRingBufferDispatcher">
</bean>

MessageRingBufferDispatcher имеет три настраиваемых свойства: strategy, bufferSize и threadNumber. В обычных условиях можно использовать настройки по умолчанию.

По умолчанию стратегия использует BlockingWaitStrategy для планирования кольцевого буфера. Если объём транзакций большой, эту стратегию можно настроить.

Значение bufferSize по умолчанию равно 1024.

threadNumber по умолчанию равен количеству потоков процессора.

Другие настройки Actor по умолчанию

Все транзакции, которые должны быть выполнены, должны наследовать интерфейс cn.ymotel.dactor.message.Message.Actor. Программа вызывает объект HandleMessage для выполнения. Если возвращаемое значение не является объектом message или равно NULL, то транзакция считается асинхронной и больше не планируется самостоятельно. После получения запроса асинхронная транзакция сама помещает сообщение обратно в очередь.

cn.ymotel.dactor.action.PlaceholderActor — это специальная транзакция, которая временно сохраняет текущую очередь и вызывает дочернюю транзакцию.

cn.ymotel.dactor.action.BeginActor — начало шага step по умолчанию в Actor.

cn.ymotel.dactor.action.EndActor — конец шага step по умолчанию в Actor.

cn.ymotel.dactor.action.JsonViewResolverActor — Actor, который возвращает Json для J2EE view.

cn.ymotel.dactor.action.ViewResolveActor — Actor для унифицированной обработки J2EE view.

cn.ymotel.dactor.action.httpclient.HttpClientActor — асинхронный вызов Actor httpClient.

cn.ymotel.dactor.action.netty.aysnsocket.TcpClientActor — асинхронный вызов Actor netty.

Пример потока транзакций

 <actor:actor id="actorhttpcore" handleException="true"  endBeanId="FinishActor" >
 
         <actor:steps>
             <actor:step xpoint="" ypont="" fromBeanId="beginActor"  conditon="" toBeanId="placeholderActor"/>
             <actor:step xpoint="" ypont=""  fromBeanId="placeholderActor" conditon="context._SUFFIX=='json'"  toBeanId="JsonViewResolverActor"/>
             <actor:step xpoint="" ypont=""  fromBeanId="placeholderActor" conditon="exception==null" toBeanId="ViewResolveActor"/>
             <actor:step xpoint="" ypont=""   fromBeanId="placeholderActor" conditon="exception!=null"  toBeanId="ErrorViewResolveActor"/>
         </actor:steps>
 
     </actor:actor>

  <actor id="randomTxt2" parent="actorhttpcore" beginBeanId="randomTxtActor">
     </actor>

Пример полного потока транзакций представлен на рисунке ниже: randomTxt2.png

Этот пример можно найти в разделе example.

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

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

Введение

Dactor — это легковесный унифицированный фреймворк для синхронного и асинхронного программирования на основе Java. Развернуть Свернуть
Отмена

Обновления

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

Участники

все

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

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