В первой части мы узнали, что такое реактивность и как с ней работать на базовом уровне. Если вы хотите продолжить изучение реактивного программирования с новым фреймворком от Spring, то добро пожаловать!
Сейчас мы разберем, что делать с полученными знаниями из прошлой статьи, а также построим небольшой веб-сервис, который будет работать в асинхронном режиме.
Для этого нам понадобятся:
- База данных MongoDB. Дело в том, что далеко не все СУБД поддерживают асинхронную работу. MongoDB в этом смысле приятно отличается и полностью поддерживает нужный нам функционал.
- Драйвер для асинхронной работы с базой данных. Обычный драйвер так не умеет.
- Spring Boot 2. На данный момент Spring Boot находится в стадии разработки, но должен выйти 18 декабря. Он нам сильно облегчит работу и сэкономит много времени.
- Gradle.Будет использован в качестве системы сборки.
- Java 8. Да, это не последняя версия на данный момент, но для наших целей вполне подойдет.
- Lombok. Поможет сократить код.
Все настройки и финальный проект можно посмотреть на github.
Приступим
Если вы еще не подключили все зависимости, то можете сделать это прямо сейчас. В gradle выглядеть они будут так:
compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
compile('org.springframework.boot:spring-boot-starter-webflux')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile(‘io.projectreactor:reactor-test')
Итак, у нас все готово. Для начала создадим пользователя нашего приложения:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document
public class User {
@Id
private String id;
private String firstName;
private String lastName;
}
Напоминаю, что для успешной компиляции и работы в IntelliJ Idea необходимо выставить галочку в пункте enable annotation processing либо написать самостоятельно все сеттеры, гетеры и конструкторы.
Далее создадим репозиторий с нашими пользователями:
import org.faoxis.habrreactivemongo.domain.User;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
public interface UserRepository extends ReactiveMongoRepository<User, String> {
}
Здесь следует заметить, что мы наследуемся от особого интерфейса для работы в реактивном режиме. Если заглянуть в интерфейс ReactiveMongoRepository, то можно увидеть, что нам возвращаются объекты, обернутые в уже знакомые нам классы Mono и Flux. Это значит, что при каком-либо обращении в БД, мы не получаем сразу же результат. Вместо этого мы получаем поток данных, из которого можно получить данные по мере готовности.
На данный момент многослойная архитектура является наиболее распространенным решением при работе с микросервисной архитектурой. Это действительно очень удобно. Давайте создадим сервисный слой. Для этого сделаем соответствующий интерфейс:
public interface UserService {
Flux<User> get();
Mono<User> save(User user);
}
Наш сервис достаточно прост, поэтому сразу создаем несколько полезных методов. И тут же реализуем их:
@Service
@AllArgsConstructor
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
@Override
public Flux<User> get() {
return userRepository.findAll();
}
@Override
public Mono<User> save(User user) {
return userRepository.save(user);
}
}
Здесь стоит заметить, что внедрение зависимости UserRepository происходит через конструктор с помощью аннотации AllArgsConstructor. На всякий случай напомню, что с некоторой версии Spring 4 можно осуществлять автоматическое внедрение зависимостей через конструктор без аннотации Autowire.
И, наконец, сделаем контроллер:
import lombok.AllArgsConstructor;
import org.faoxis.habrreactivemongo.domain.User;
import org.faoxis.habrreactivemongo.service.UserService;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/users")
@AllArgsConstructor
public class UserController {
private UserService userService;
@PostMapping
public Mono<User> post(@RequestBody User user) {
return userService.save(user);
}
@GetMapping
public Flux<User> get() {
return userService.get();
}
}
Запустим наше приложение. Все должно работать. Теперь сделаем POST запрос на localhost:8080/users со следующим содержимым:
{
"firstName": "Peter",
"lastName": "Griffin"
}
В ответ мы получим такой же объект, но с присвоенным ему id:
{
"id": "5a0bf0fdc48fd53478638c9e",
"firstName": "Peter",
"lastName": "Griffin"
}
Отлично! Давайте сохраним еще пару пользователей и попробуем посмотреть, что у нас уже есть в БД. У меня такой результат GET запроса на localhost:8080/users:
[
{
"id": "5a0bf0fdc48fd53478638c9e",
"firstName": "Peter",
"lastName": "Griffin"
},
{
"id": "5a0bf192c48fd53478638c9f",
"firstName": "Lois",
"lastName": "Griffin"
},
{
"id": "5a0bf19ac48fd53478638ca0",
"firstName": "Mag",
"lastName": "Griffin"
}
]
Отлично! У нас есть целый сервис, который работает в асинхронном режиме! Но есть еще кое-что, о чем следует помнить. Работа с асинхронным репозиториями может очень сильно поменять вид сервиса, который получает данные из него.
Чтобы продемонстрировать это, создадим еще один обработчик URL метода в нашем контроллере:
@GetMapping("{lastName}")
public Flux<User> getByLastName(@PathVariable(name = "lastName") String lastName) {
return userService.getByLastName(lastName);
}
Здесь все просто. Мы получаем фамилию пользователя и выводим всех людей с такой фамилией.
Конечно, такую логику можно возложить на базу данных, но здесь я хотел бы обратить внимание, как это будет выглядит в сервисе:
@Override
public Flux<User> getByLastName(final String lastName) {
return userRepository
.findAll()
.filter(user -> user.getLastName().equals(lastName));
}
Обратите внимание, что есть разница в работе с данными и потоками данных. Обычно мы осуществляем какие-то действия над данными непосредственно. Здесь ситуация другая. Мы говорим, что следует сделать в потоке данных.
Попробуем сделать GET запрос по URL localhost:8080/users/Griffin. У меня такой результат:
[
{
"id": "5a0bf0fdc48fd53478638c9e",
"firstName": "Peter",
"lastName": "Griffin"
},
{
"id": "5a0bf192c48fd53478638c9f",
"firstName": "Lois",
"lastName": "Griffin"
},
{
"id": "5a0bf19ac48fd53478638ca0",
"firstName": "Mag",
"lastName": "Griffin"
}
]
В этой статье мы рассмотрели, как построить асинхронный сервис с новым фреймворком WebFlux и сервером Netty (он идет из коробки по умолчанию). Также мы убедились, как легко этого достичь со Spring Boot 2. Если у вас на проекте микросервисная архитектура, то скорее всего вы легко сможете при желании перевести свои приложения на WebFlux с выходом Spring Boot 2(если, конечно, в этом есть потребность).
P.S. Есть несколько идей по продолжению. Если вам интересен материал, и вы не против моей подачи, то в следующих частях мы можем рассмотреть, например, асинхронное взаимодействие между приложениями. Спасибо за внимание!
Источник: https://habrahabr.ru/post/342506/?utm_source=habrahabr&utm_medium=rss&utm_campaign=interesting
Смотри также:
- Зачем нужна Java. http://fetisovvs.blogspot.com/2014/07/java.html
- JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
- Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
- Java-ресурсы, на которые есть смысл подписаться. http://fetisovvs.blogspot.com/2016/09/java-java.html
- Подборка популярных ошибок начинающих Java программистов. http://fetisovvs.blogspot.com/2016/10/java-java_29.html
- Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
- Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
- Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
- Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
- Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
- ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
- Integer и int. http://fetisovvs.blogspot.com/2016/07/integer-int-java.html
- Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
- Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
- Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
- Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
- В чем разница между Set и Set. Пример использования Set. http://fetisovvs.blogspot.com/2016/09/set-set-set-java.html
- Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
- Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
- Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
- Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
- Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
- Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
- 1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
- Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
- Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson, LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
- Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
- Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
- Работа с Bluetooth LE из Java-приложений. http://fetisovvs.blogspot.com/2016/07/bluetooth-le-java-java.html
- Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html
- Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
- Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
- Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Комментариев нет:
Отправить комментарий