Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 11 лет назад пользователемwww.addconf.ru
1 СИСТЕМА ОБРАБОТКИ БИЗНЕС-ЛОГИКИ SERVER-SIDE ПРИЛОЖЕНИЯ НА GROOVY Александр Шлянников Digital Zone
2 Задача Возможность изменять бизнес-логику server-side Java EE приложения «на лету»: С минимальными обращениями к разработчикам системы Без перекомпиляции Без shutdown/redeploy системы на сервере С защитой от синтаксических и семантических ошибок
3 Применение Биллинговые системы: Операторы связи Такси Генерация разнообразных отчетов Пример: «Клиенту, сделавшему 3 заказа в прошлом месяце и с днем рождения на этой неделе, сделать скидку в 10% после 15-й минуты поездки»
4 Типичные решения Фиксированные параметры и настройки логики – недостаточно гибко Скриптинг: JavaScript (Mozilla Rhino, Groovy (
5 Groovy Dynamic language for the Java Virtual Machine: Динамическая типизация Удобный и краткий синтаксис работы с коллекциями, картами, массивами, строками Возможность runtime-компиляции в JVM байт-код и работы с другим Java кодом и библиотеками
6 Архитектура Java EE – JBoss Application Server ORM – EJB JPA Persistence (Stateless & Entity Beans) Service MBeans HTTP/SOAP Client Connectors
7 Сервис команд Service MBean: Invoker: Object invoke(String mapping, Object[] args) Commands: Object invoke(Object[] args)
8 Оформление команд Команда: Groovy Script (класс) Runtime компиляция в JVM байт-код, создание объектов и хранение в памяти: GroovyClassLoader loader = new GroovyClassLoader(); Class groovyClass = loader.parseClass(content); GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance(); Файлы исходников команд расположены вне EAR/WAR/SAR-архивов Мониторинг изменений директории исходников через JBoss Deployer для runtime отслеживания изменений
9 Класс команды Аннотация на класс – mapping Имплементация Java интерфейса: public interface GenericScript { void init(Object... args); Object invoke(Object... args); void onInterrupt(Object... args); } Хранение скомпилированных объектов в сервисе в виде ассоциативного массива [Mapping -> Object] Выполнение прямым вызовом метода invoke без использования Reflections: GenericScript s = scripts.get(mapping); s.invoke(args); Object] Выполнение прямым вызовом метода invoke без использования Reflections: GenericScript s = scripts.get(mapping); s.invoke(args);">
10 Базовый контекст выполнения скрипта Новое выполнение – новый объект (аналогично HttpServletRequest ) Утилитные методы: Object getAttribute(String key); void setAttribute(String key, Object value); Object invoke(String mapping, Object[] args); void log(String message);
11 Типы команд Разделение контекстов выполнения команд: Calculation (базовый): без доступа к Persistence Read-only: с доступом к Persistence на чтение Read/Write: с доступом к Persistence на чтение/обновление
12 Организация доступа к данным EJB JPA Persistence: Все сущности предметной области Утилитный Stateless Bean: public interface BaseDAO { List getAll(Class c); List getEntitiesByKey(Class c, String key, Object value); T getEntityById(Class c, Object id); T createEntity(T entity); void mergeEntity(Object entity); void removeEntity(Class c, Object id); } Методы Stateless Bean доступны через контекст скрипта
13 Организация доступа к данным Имплементация Stateless Bean, примеры: T createEntity(T entity) { entityManager.persist(entity); return entity; } List getAll(Class c) { Query query = entityManager.createQuery("select c from " + c.getName() + " c"); return query.getResultList(); }
14 Управление транзакцией Работа с транзакцией в Stateless = = TransactionManagementType.BEAN) При использовании CMT – аннотации … sessionContext.setRollbackOnly();// откат В обоих случаях, нельзя: myStatelessBean.startTransaction(); doSomething(); myStatelessBean.commitTransaction();
15 Управление транзакцией Решение: Специальные методы-обертки в Stateless Bean: //для Read/Write public Object wrapTransactionRequired(ScriptWrapper sw) //для Read-Only public Object wrapTransactionSupports(ScriptWrapper sw) Вызов метода invoke скрипта-команды и связывание с Stateless Bean – внутри методов wrapTransactionRequired и wrapTransactionSupports
16 Многопоточное исполнение Исполнение в очереди - ExecutorService: singleThreadExecutor: один поток, контроль времени выполнения multiThreadExecutor: несколько потоков, контроль времени выполнения debugThreadExecutor: несколько потоков, без контроля времени выполнения Определение типа команды и таймаута выполнения в аннотации к ScriptMapping { //… long runTimeout() default -1; ScriptThreadingType type() default ScriptThreadingType.MULTI; }
17 Контроль времени выполнения Два вложенных Callable на выполнение команды: 1) Внутренний: запуск скрипта 2) Внешний: контроль времени выполнения через FutureTask.get(timeout) Внутренний ExecutorService на N+1 поток
18 Контроль времени выполнения 1) TimeoutException в FutureTask.get(timeout) 2) Вызов метода onInterrupt() у скрипта команды для предупреждения о завершении 3) sleep(timeout) 4) stop() у потока 5) Запись в журнал ошибок
19 Асинхронный режим Вызывающий клиент имплементирует Callback для взаимодействия с командой во время выполнения, а получает Future:
20 Контроль ошибок 1) Проверка синтаксиса при компиляции: GroovyClassLoader loader = new GroovyClassLoader(); Class groovyClass = loader.parseClass(content); - throws CompilationFailedException при синтаксическиой ошибке 2) Проверка времени исполнения по таймауту 3) При таймауте скрипта больше K раз – исключение из Invoker
21 Отладка Поддержка синтаксиса Groovy в IDE Удаленная отладка (JPDA) из IDE Выполнение в отдельном потоке без контроля таймаута
22 Интерфейс администрирования Create, Read, Update, Delete команд Версионность для отката изменений Мониторинг: Количество команд в очереди Exceptions Отключенные команды
23 = "/SetOrderToBoard", runTimeout = 10000L) class SetOrderToBoard extends ReadWriteScript { def invoke(context, orderUuid, boardUuid) { def success = false; def order = context.findByKey("Order", "uuid", orderUuid); def boards = context.findAll("Board"); for (board in boards) { if (board.status == "free") { board.currentOrder = order; order.board = board; if (new Date().getTime() - order.creationTime > 10*60* 1000) { order.discount += 10; } context.update(board); context.update(order); success = true; break; } return success; } 10*60* 1000) { order.discount += 10; } context.update(board); context.update(order); success = true; break; } return success; }">
24 Другие платформы Эквивалентное выполнение скриптов:.NET - перенос в контекст отличающихся по синтаксису методов: sqrt, pow, round, equal, etc
25 Выводы Разработанный сервис: Глубокая настройка бизнес-логики приложения Понятный юзерам язык и API Работа с сущностями предметной области системы Защита от ошибок Возможность расширения на другие платформы
26 Спасибо за внимание!
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.