Реактивное программирование с применением RxJava
Покупка
Тематика:
Программирование на Java
Издательство:
ДМК Пресс
Перевод:
Слинкин Алексей Александрович
Год издания: 2017
Кол-во страниц: 358
Дополнительно
Вид издания:
Практическое пособие
Уровень образования:
ВО - Бакалавриат
ISBN: 978-5-97060-496-0
Артикул: 698120.02.99
Доступ онлайн
В корзину
В наши дни, когда программы асинхронны, а быстрая реакция - важнейшее свойство, реактивное программирование поможет писать более надежный, лучше масштабируемый и быстрее работающий код. Благодаря этой книге программист на Java узнает о реактивном подходе к задачам и научится создавать программы, вобравшие в себя лучшие черты этой новой и весьма перспективной парадигмы. Данная книга содержит глубокое и подробное изложение концепций и принципов использования реактивного программирования вообще и Rxjava в частности. Книга может использоваться как для последовательного изучения предмета, так и в качестве справочника по библиотеке.
Тематика:
ББК:
УДК:
ОКСО:
- ВО - Бакалавриат
- 09.03.01: Информатика и вычислительная техника
- 09.03.02: Информационные системы и технологии
- 09.03.03: Прикладная информатика
- 09.03.04: Программная инженерия
ГРНТИ:
Скопировать запись
Фрагмент текстового слоя документа размещен для индексирующих роботов.
Для полноценной работы с документом, пожалуйста, перейдите в
ридер.
Томаш Нуркевич, Бен Кристенсен Реактивное программирование с применением RxJava
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo Reactive Programming with RxJava Creating Asynchronous, Event-Based Applications Tomasz Nurkiewicz and Ben Christensen
Москва, 2017 Реактивное программирование с применением RxJava Разработка асинхронных событийно-ориентированных приложений Томаш Нуркевич, Бен Кристенсен
УДК 004.738.5:004.438 RxJava ББК 32.973.2 М15 М15 Томаш Нуркевич, Бен Кристенсен Реактивное программирование с применением RxJava / пер. с англ. Слинкин А. А. – М.: ДМК Пресс, 2017. – 358 с.: ил. ISBN 978-5-97060-496-0 В наши дни, когда программы асинхронны, а быстрая реакция – важ нейшее свойство, реактивное программирование поможет писать более надежный, лучше масштабируемый и быстрее работающий код. Благодаря этой книге программист на Java узнает о реактивном подходе к задачам и научится создавать программы, вобравшие в себя лучшие черты этой новой и весьма перспективной парадигмы. Данная книга содержит глубокое и подробное изложение концепций и принципов использования реактивного программирования вообще и RxJava в частности. Книга может использоваться как для последовательного изучения пред мета, так и в качестве справочника по библиотеке. УДК 004.738.5:004.438 RxJava ББК 32.973.2 Authorized Russian translation of the English edition of Reactive Programming with RxJava, ISBN 9781491931653. © 2017 Ben Christensen and Tomasz Nurkiewicz. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность технических ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим издательство не несет ответственности за возможные ошибки, связанные с использованием книги. ISBN 978-1-49193-165-3 (англ.) © Ben Christensen and Tomasz Nurkiewicz, 2017. ISBN 978-5-97060-496-0 (рус.) © Перевод на русский язык, оформление, издание, ДМК Пресс, 2017
Посвящается Паулине Сьцежка, самому честному и прямому человеку из всех моих знакомых. За доверие и помощь, отнюдь не ограничивающуюся написанием книги. За мою жизнь, которую она изменила в куда большей степени, чем может себе представить. – Томаш Нуркевич
Оглавление Предисловие..................................................................11 Вступление....................................................................14 Для кого написана эта книга ................................................................. 14 Несколько слов от Бена Кристенсена .................................................... 14 Несколько слов от Томаша Нуркевича ................................................... 16 О содержании книги ............................................................................. 16 Ресурсы в Сети ..................................................................................... 17 Графические выделения ....................................................................... 17 Как с нами связаться ............................................................................ 18 Благодарности ..................................................................................... 18 От Бена ........................................................................................................ 18 От Томаша .................................................................................................... 19 Глава.1..Реактивное.программирование.. с.применением.RxJava.....................................................20 Реактивное программирование и RxJava .............................................. 20 Когда возникает нужда в реактивном программировании ..................... 22 Как работает RxJava .............................................................................. 23 Проталкивание и вытягивание ...................................................................... 23 Синхронный и асинхронный режим .............................................................. 25 Конкурентность и параллелизм .................................................................... 28 Ленивые и энергичные типы ......................................................................... 31 Двойственность ........................................................................................... 33 Одно или несколько? .................................................................................... 34 Учет особенностей оборудования: блокирующий и неблокирующий ввод-вывод ........................................................................................... 39 Абстракция реактивности ..................................................................... 44 Глава.2..Реактивные.расширения.......................................45 Анатомия rx.Observable ......................................................................... 45 Подписка на уведомления от объекта Observable .................................. 48 Получение всех уведомлений с помощью типа Observer<T> ........................ 50 Управление прослушивателями с помощью типов Subscription и Subscriber<T> .................................................................................... 50
Оглавление Создание объектов Observable ............................................................. 52 Подробнее о методе Observable.create() ...................................................... 53 Бесконечные потоки ..................................................................................... 56 Хронометраж: операторы timer() и interval() .................................................. 61 Горячие и холодные объекты Observable ....................................................... 61 Практический пример: от API обратных вызовов к потоку Observable .... 63 Управление подписчиками вручную ............................................................. 68 Класс rx.subjects.Subject ....................................................................... 69 Тип ConnectableObservable ................................................................... 71 Реализация единственной подписки с помощью publish().refCount() ............ 72 Жизненный цикл ConnectableObservable ...................................................... 74 Резюме ................................................................................................. 77 Глава.3..Операторы.и.преобразования................................79 Базовые операторы: отображение и фильтрация .................................. 79 Взаимно однозначные преобразования с помощью map() ........................... 81 Обертывание с помощью flatMap() ............................................................... 85 Откладывание событий с помощью оператора delay() .................................. 90 Порядок событий после flatMap() ................................................................. 91 Сохранение порядка с помощью concatMap() .............................................. 93 Более одного объекта Observable ......................................................... 95 Обращение с несколькими объектами Observable, как с одним, с помощью merge() ...................................................................................... 95 Попарная композиция с помощью zip() и zipWith() ........................................ 97 Когда потоки не синхронизированы: combineLatest(), withLatestFrom() и amb() ........................................................................................................100 Более сложные операторы: collect(), reduce(), scan(), distinct() и groupBy() ......................................................................................... 106 Просмотр последовательности с помощью Scan и Reduce ..........................106 Редукция с помощью изменяемого аккумулятора: collect() ..........................108 Проверка того, что Observable содержит ровно один элемент, с помощью single() ......................................................................................109 Устранение дубликатов с помощью distinct() и distinctUntilChanged().... 110 Выборка с помощью операторов skip(), takeWhile() и прочих .......................112 Способы комбинирования потоков: concat(), merge() и switchOnNext() ........114 Расщепление потока по условию с помощью groupBy() ...............................121 Написание пользовательских операторов........................................... 125 Повторное использование операторов с помощью compose().....................125 Реализация более сложных операторов с помощью lift() .............................127 Резюме ............................................................................................... 133 Глава.4..Применение.реактивного.программирования. в.существующих.приложениях.........................................134 От коллекций к Observable .................................................................. 135 BlockingObservable: выход из реактивного мира ................................. 135
Оглавление О пользе лени ..................................................................................... 138 Композиция объектов Observable ....................................................... 140 Ленивое разбиение на страницы и конкатенация ........................................141 Императивная конкурентность ........................................................... 142 flatMap() как оператор асинхронного сцепления ................................. 148 Замена обратных вызовов потоками ................................................... 153 Периодический опрос изменений ....................................................... 156 Многопоточность в RxJava .................................................................. 157 Что такое диспетчер? ..................................................................................158 Декларативная подписка с помощью subscribeOn() .....................................167 Конкурентность и поведение subscribeOn() .................................................171 Создание пакета запросов с помощью groupBy() ........................................175 Декларативная конкурентность с помощью observeOn() ..............................177 Другие применения диспетчеров ................................................................180 Резюме ............................................................................................... 181 Глава.5..Реактивность.сверху.донизу................................183 Решение проблемы C10k .................................................................... 183 Традиционные HTTP-серверы на основе потоков ........................................185 Неблокирующий HTTP-сервер на основе Netty и RxNetty .............................187 Сравнение производительности блокирующего и реактивного сервера .....195 Обзор реактивных HTTP-серверов ..............................................................200 Код HTTP-клиента ............................................................................... 201 Доступ к реляционной базе данных ..................................................... 205 NOTIFY и LISTEN на примере PostgreSQL .....................................................207 CompletableFuture и потоки ................................................................. 211 Краткое введение в CompletableFuture ........................................................211 Сравнение типов Observable и Single .................................................. 220 Создание и потребление объектов типа Single ............................................221 Объединение ответов с помощью zip, merge и concat ..................................223 Интероперабельность с Observable и CompletableFuture ..................... 225 Когда использовать тип Single? ...................................................................226 Резюме ............................................................................................... 227 Глава.6..Управление.потоком.и.противодавление................228 Управление потоком ........................................................................... 228 Периодическая выборка и отбрасывание событий ......................................228 Скользящее окно ........................................................................................237 Пропуск устаревших событий с помощью debounce()..................................238 Противодавление ............................................................................... 243 Противодавление в RxJava ..........................................................................244 Встроенное противодавление .....................................................................247 Производители и исключение MissingBackpressureException ......................250 Учет запрошенного объема данных .............................................................253 Резюме ............................................................................................... 259
Оглавление Глава.7..Тестирование.и.отладка......................................260 Обработка ошибок .............................................................................. 260 А где же мои исключения? ...........................................................................261 Декларативная замена try-catch ..................................................................264 Таймаут в случае отсутствия событий ..........................................................268 Повтор после ошибки ..................................................................................271 Тестирование и отладка ...................................................................... 275 Виртуальное время .....................................................................................275 Диспетчеры и автономное тестирование ....................................................277 Автономное тестирование...........................................................................279 Мониторинг и отладка......................................................................... 287 Обратные вызовы doOn…() .........................................................................287 Измерение и мониторинг ............................................................................289 Резюме ............................................................................................... 292 Глава.8..Практические.примеры.......................................293 Применение RxJava в разработке программ для Android ..................... 293 Предотвращение утечек памяти в компонентах Activity ................................294 Библиотека Retrofit со встроенной поддержкой RxJava ...............................296 Диспетчеры в Android ..................................................................................301 События пользовательского интерфейса как потоки ...................................304 Управление отказами с помощью Hystrix............................................. 307 Hystrix: первые шаги ....................................................................................308 Неблокирующие команды и HystrixObservableCommand ..............................310 Паттерн Переборка и быстрое прекращение ...............................................311 Пакетирование и объединение команд .......................................................313 Мониторинг и инструментальные панели ....................................................318 Опрос баз данных NoSQL .................................................................... 321 Клиенстский API Couchbase ........................................................................322 Клиентский API MongoDB ............................................................................323 Интеграция с Camel ............................................................................ 325 Потребление файлов с помощью Camel ......................................................325 Получение сообщений от Kafka ...................................................................326 Потоки Java 8 и CompletableFuture ...................................................... 326 Полезность параллельных потоков ..............................................................328 Выбор подходящей абстракции конкурентности .........................................330 Когда выбирать Observable? ........................................................................331 Потребление памяти и утечки ............................................................. 332 Операторы, потребляющие неконтролируемый объем памяти ....................332 Резюме ............................................................................................... 337 Глава.9..Направления.будущего.развития..........................338 Реактивные потоки ............................................................................. 338 Типы Observable и Flowable ................................................................. 338 Производительность .......................................................................... 339
Оглавление Миграция ............................................................................................ 340 Приложение.А..Дополнительные.примеры.. HTTP-серверов..............................................................341 Системный вызов fork() в программе на C .......................................... 341 Один поток – одно подключение ......................................................... 343 Пул потоков для обслуживания подключений ..............................................345 Приложение.B..Решающее.дерево.для.выбора.. операторов.Observable...................................................347 Об.авторах...................................................................352 Об.изображении.на.обложке............................................352 Предметный.указатель...................................................353
Предисловие 28 октября 2005 года Рэй Оззи (Ray Ozzie), только что назначенный главным архитектором Майкрософт, разослал своим сотрудникам получившее скандальную известность письмо, озаглавленное «Крах Интернет-служб». В нем он по сути дела описывает тот мир, который мы знаем сегодня, – мир, где такие корпорации, как Microsoft, Google, Facebook, Amazon и Netflix используют веб в качестве основного канала доставки своих услуг. В письме Оззи есть мысль, которую разработчики не часто слышат от топменеджеров крупной корпорации: Сложность убивает. Она высасывает соки из разработчиков, затрудняет планирование, сборку и тестирование продуктов, порождает проблемы в части безопасности и служит причиной горьких разочарований пользователей и администраторов. Прежде всего, следует принять во внимание, что в 2005 году крупные ИТкомпании были всем сердцем влюблены в умопомрачительно сложные технологии типа SOAP, WS-* и XML. В то время еще не было слова «микросервисы» и даже на горизонте не просматривалась простая технология, которая позволила бы разработчикам справиться с проблемами составления асинхронной композиции простых служб для получения более сложных, не упуская из виду такие аспекты, как обработка ошибок, задержки, безопасность и эффективность. Для моей группы облачных программных продуктов письмо Оззи стало призывом не заниматься ерундой, а сосредоточиться на придумывании простой модели программирования, которая позволит создавать крупномасштабные асинхронные архитектуры Интернет-служб для работы с большими объемами данных. После многих фальстартов на нас наконец снизошло озарение: взяв за основу интерфейсы Iterable/Iterator для синхронных коллекций, мы могли бы получить пару интерфейсов для представления потоков асинхронных событий и применять всем хорошо знакомые операции над последовательностями – map, filter, scan, zip, groupBy и другие – к преобразованию и комбинированию асинхронных потоков данных. Так летом 2007 года родилась идея Rx. В процессе реализации мы поняли, что необходимо как-то управлять конкурентностью и временем и с этой целью обобщили идею исполнителей в Java, дополнив ее виртуальным временем и кооперативной многозадачностью. После напряженной двухлетней работы, когда были опробованы и отвергнуты разнообразные проектные решения, 18 ноября 2009 года мы наконец выпустили
Предисловие первую версию Rx.NET. Вскоре после этого мы перенесли Rx на Microsoft.Phone. Reactive для Windows Phone 7 и приступили к реализации Rx на таких языках, как JavaScript и C++, а заодно поэкспериментировали с Ruby и Objective-C. Внутри Майкрософт первым пользователем Rx стал Джафар Хусейн (Jafar Husain), эту технологию он взял с собой, когда перешел в Netflix в 2011 году. Джафар всячески пропагандировал Rx в компании и в конце концов полностью переделал клиентскую часть пользовательского интерфейса Netflix на основе асинхронной обработки потоков. И, к счастью для всех нас, он заразил своим энтузиазмом Бена Кристенсена, занимавшегося в Netflix разработкой API промежуточного уровня. В 2012 году Бен начал работать над RxJava и в начале 2013 разместил весь код на Github, сделав его открытым. Еще одним из ранних приверженцев Rx в Майкрософт был Пол Беттс (Paul Betts), позже он перешел в Github и убедил коллег, в т. ч. Джастина Спар-Саммерса (Justin Spahr-Summers) реализовать и выпустить ReactiveCocoa для Objective-C, что и произошло весной 2012. Поскольку Rx завоевывал популярность в отрасли, мы убедили отдел Microsoft Open Tech раскрыть код Rx.NET, это случилось осенью 2012. Вскоре после этого я ушел из Майкрософт, основал компанию Applied Duality и посвятил все свое время тому, чтобы сделать Rx стандартным кросс-языковым и кросс-платформенным API для асинхронной обработки потоков данных в режиме реального времени. К 2016 году популярность Rx стремительно возросла, как и число пользователей. Весь трафик, проходящий через Netflix API, обрабатывается RxJava. То же можно сказать о библиотеке обеспечения отказоустойчивости Hystrix, лежащей в основе всего внутреннего трафика службы, и сопутствующих реактивных библиотеках RxNetty и Mantis. Сейчас Netflix работает над полностью реактивным сетевым стеком для связывания всех внутренних служб, пересекающих границы процессов и машин. RxJava нашла также весьма полезные применения в экосистеме Android. Компании SoundCloud, Square, NYT, Seatgeek используют RxJava в своих приложениях и вносят вклад в разработку дополнительной библиотеки RxAndroid. Такие поставщики NoSQL-решений, как Couchbase и Splunk, также предлагают основанные на Rx интерфейсы к уровню доступа к данным. Среди других Java-библиотек, воспринявших RxJava, упомянем Camel Rx, Square Retrofit и Vert.x. В сообществе JavaScript широко распространена библиотека RxJS, лежащая в основе популярного каркаса Angular 2. Сообщество поддерживает сайт http://reactivex.io/, на котором можно найти информацию о реализациях Rx на многих языках, а также фантастические камешковые диаграммы с пояснениями, созданные Дэвидом Гроссом (@CallHimMoorlock). С самого начала проект Rx развивался в соответствии с потребностями сообщества разработчиков и при его активном участии. В оригинальной реализации Rx в .NET упор был сделан, прежде всего, на преобразовании асинхронных потоков событий и использовании асинхронных перечислимых объектов в ситуациях, где требуется противодавление. Поскольку в Java нет языковой поддержки асинхронного ожидания, сообщество дополнило типы Observer и Observable концепцией реактивного вытягивания и добавило интерфейс Producer. Благодаря усилиям
Предисловие многих разработчиков реализация RxJava получилась весьма изощренной и в высшей степени оптимизированной. Несмотря на то что детали RxJava несколько отличаются от других реализаций Rx, библиотека все равно ориентирована специально на разработчиков, стремящихся выжить в прекрасном новом мире распределенной обработки данных в реальном времени и сконцентрироваться на эссенциальной, а не акцидентальной сложности, высасывающей из нас все соки. Эта книга содержит глубокое и подробное изложение концепций и принципов использования Rx вообще и RxJava в частности, написанное двумя авторами, которые потратили бессчетное количество часов на реализацию RxJava и применение ее к реальным задачам. Если вам нужна «реактивность», то лучшего способа, чем купить книгу, не придумаешь. – Эрик Мейер, основатель и президент компании Applied Duality, Inc.
Вступление Для.кого.написана.эта.книга Книга ориентирована на Java-программистов средней и высокой квалификации. Читатель должен свободно владеть языком Java, но предварительное знакомство с реактивным программированием не предполагается. Многие описываемые концепции относятся к функциональному программированию, но знакомство с ним также не обязательно. Особенно полезна книга будет двумя группам программистов. • Профессионалы, которым нужно повысить производительность сервера или сделать код для мобильных устройств более удобным для сопровождения. Если вы из их числа, то найдете здесь идеи и готовые решения реальных проблем, а также практические советы. А RxJava тогда следует считать просто еще одним инструментом, который книга поможет освоить. • Любопытные разработчики, которые слыхали о реактивном программировании или конкретно о RxJava и хотели бы понять, что это такое. Если вы относите себя к этой категории и не планируете немедленно использовать преимущества RxJava в производственном коде, то книга заметно обогатит ваш багаж знаний. Наконец, это книга станет подспорьем для практикующего архитектора программного обеспечения. RxJava оказала сильное влияние на общую архитектуру целых систем, поэтому знать об этой технологии полезно. Но даже если вы только начинаете путешествие в мир программирования, все равно попробуйте прочитать первые главы, в которых объяснены основы. Понятия преобразования и композиции универсальны и не являются спецификой реактивного программирования. Несколько.слов.от.Бена.Кристенсена В 2012 году я работал над новой архитектурой Netflix API. По ходу дела стало ясно, что для достижения поставленных целей необходимо включить конкурентность и асинхронные сетевые запросы. Исследуя различные подходы, я столкнулся с Джафаром Хусейном (https://github.com/jhusain), который попытался заинтересовать меня технологией Rx, с которой познакомился, работая в Майкрософт. В то время я довольно сносно владел техникой конкурентного программирования,
Вступление но размышлял о нем в императивных терминах и преимущественно с точки зрения Java, поскольку именно программированием на Java зарабатывал себе на хлеб. Поэтому мне трудно было воспринять пропагандируемый Джафаром подход из-за его функциональной ориентированности, и я не поддавался на его убеждения. За этим последовали месяцы споров и дискуссий, архитектура системы становилась все более зрелой, а мы с Джафаром снова и снова встречались у доски, пока я, наконец, не врубился в теоретические принципы, а затем и не оценил элегантность и эффективность подходов, предлагаемых Rx. Мы решили включить модель программирования Rx в Netflix API и в конечном итоге создали реализацию на Java, которую назвали RxJava, следуя заданным Майкрософт образцам: Rx.Net и RxJS. За примерно три года, когда создавалась библиотека RxJava, по большей части на GitHub, в виде открытого кода, я имел удовольствие работать с растущим сообществом и соавторами, каковых было 120 с лишним, и вместе нам удалось превратить RxJava в зрелый продукт, используемый во многих системах как на стороне сервера, так и на стороне клиента. Он собрал больше 15 000 звезд на GitHub, что позволило войти в первые 200 проектов (https://github.com/search?p=11&q= stars:%3E1&s=stars&type=Repositories) и занять третье место среди проектов на Java (https://github.com/search?l=Java&p=1&q=stars:%3E1&s=stars&type=Repositories). Джордж Кэмпбелл (George Campbell), Аарон Талл (Aaron Tull) и Мэтт Джекобс (Matt Jacobs) из Netflix много сделали для превращения RxJava из первых сборок в то, чем она является теперь. В частности, им проект обязан добавлением lift, Subscriber, противодавления и поддержки других языков на базе JVM. Дэвид Карнок (David Karnok) присоединился к проекту позже, но уже обошел меня по числу фиксаций и написанных строк кода. Ему проект в значительной мере обязан своим успехом, а теперь он возглавил его. Хочу поблагодарить Эрика Мейера, который создал Rx во время работы в Майкрософт. С тех пор как он уволился оттуда, я урывками общался с ним в Netflix, когда трудился над RxJava, а теперь счастлив работать вместе в Facebook. Я считаю большой честью обсуждать с ним различные вопросы у доски и учиться у него. С таким наставником, как Эрик, поднимаешься на новый уровень мышления. Попутно мне приходилось много раз выступать на конференциях с докладами о RxJava и реактивном программировании, и я повстречал много людей, которые помогли мне узнать о коде и архитектуре куда больше, чем я мог бы достичь собственными силами. Netflix оказала мне феноменальное содействие, позволяя тратить время и силы на этот проект и выделив специалистов для написания технической документации, – сам я с этим точно не справился бы. Проект с открытым исходным кодом такого масштаба и качества никогда не стал бы успешным, если бы у меня не было возможности заниматься им в рабочее время и привлекать людей с разными знаниями и умениями. Первая глава книги представляет собой мою попытку объяснить, почему реактивное программирование вообще полезно и как конкретно в RxJava реализованы общие принципы.
Доступ онлайн
В корзину