DActor
Введение
DActor — это фреймворк, основанный на идее сопрограмм. Он позволяет одновременно работать с синхронным и асинхронным кодом, упрощая разработку асинхронного кода. DActor сочетает в себе преимущества асинхронного программирования (высокая степень параллелизма, отсутствие блокировок) и синхронного (простота и удобство сопровождения).
Основные цели DActor:
Адрес проекта
GitHub: https://github.com/allon2/dactor GitEE: https://gitee.com/handyun/dactor
Документация
QQ группа для общения 783580303
Интеграция с системами Dpress — многодоменный блог на основе Dactor.
Текущие модели разработки
Дизайн
Цель дизайна — сохранить высокую производительность асинхронной обработки, упростить разработку асинхронных программ и сделать код более понятным. Процесс обработки включает в себя следующие шаги:
Особенности
Требования к среде
Примечание
Рекомендуется избегать использования 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 следующим образом:
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 по умолчанию равен количеству потоков процессора.
Все транзакции, которые должны быть выполнены, должны наследовать интерфейс 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>
Пример полного потока транзакций представлен на рисунке ниже:
Этот пример можно найти в разделе example.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )