Как асинхронная неблокируемая структура ввода-вывода (NIO), Netty используется для быстрой разработки поддержки масштабируемых протокольных серверов и клиентов. Создание низкоуровневых сетевых серверов и клиентов относительно просто с Netty. Разработчики могут работать на уровне сокетов, например, создавать оригинальные протоколы связи между клиентами и серверами.
Netty поддерживает все блокирующие и неблокирующие унифицированные API-интерфейсы, модель сменяемых потоков и SSL / TLS. Все запросы выполняются асинхронно в отдельном потоке с неблокирующим сервером (функция не должна блокировать цикл обработки событий). Это противоречит модели блокирующего сервера, которая обычно использует отдельный поток для выполнения каждого запроса. Без необходимости переключения или создания потоков при увеличении нагрузки неблокируемая модель снижает накладные расходы и ускоряет разработку по мере расширения трафика.
Однако вся эта сила достигается за счет сложности. Неблокирующий код обычно труднее читать, тестировать и поддерживать, хотя он значительно улучшился по мере развития асинхронной парадигмы. Поскольку Netty работает на уровне сокетов, это также требует более глубокого понимания основных моментов, таких как циклы потоков, байтовые буферы и управление памятью.
Команда Netty.io сделала замечательную работу по упрощению использования Netty при всей его мощности, но она по-прежнему более сложна, чем библиотеки более высокого уровня (такие как Spring Boot WebFlux). Так зачем его использовать?
Netty разработан для того, чтобы сделать реализацию пользовательских сетевых протоколов относительно простой. HTTP хорош, но это универсальный протокол, в основном хорошо подходящий для большинства вещей. Но если вы постоянно передаете пользовательские структурированные данные между серверами и клиентами (большие файлы, потоковое мультимедиа, игровые данные в реальном времени и т. Д.), Вы можете добиться большего. Netty позволяет вам писать свой собственный сетевой протокол, адаптированный к вашим конкретным требованиям, оптимизируя поток трафика для вашей конкретной ситуации, без лишних затрат, таких как HTTP или FTP.
Однако, даже если вы не собираетесь писать свой собственный протокол TCP, вы все равно можете использовать возможности Netty. Spring WebFlux — это ответ Spring на неблокирующее и реактивное программирование. Это альтернатива традиционной (блокирующей) архитектуре Spring MVC. По умолчанию Spring Boot WebFlux Starter работает на встроенном сервере Netty. В этой конфигурации вы можете думать о WebFlux как о реактивном, неблокирующем прикладном уровне HTTP, построенном на основе совершенства сокетов NIO от Netty.
В этом руководстве вы создадите простое приложение «Hello world» в Netty. Затем вы создадите такое же приложение «Hello world» в Spring Boot WebFlux. Наконец, вы собираетесь добавить в приложение имя входа OAuth 2.0, используя Okta в качестве поставщика OAuth 2.0 .
Установите зависимости проекта
Этот проект имеет несколько необходимых инструментов для установки, прежде чем начать.
Java 11 : этот проект использует Java 11. Вы можете установить OpenJDK, следуя инструкциям на веб-сайте OpenJDK или используя SDKMAN .
HTTPie : это простая утилита командной строки для создания HTTP-запросов, которую вы будете использовать для тестирования приложения REST. Это также любимый разработчиками Okta. Установите в соответствии с инструкциями на их сайте .
Учетная запись разработчика Okta : вы будете использовать Okta в качестве поставщика OAuth / OIDC для добавления аутентификации входа OAuth2 в приложение. Зарегистрируйте бесплатную учетную запись разработчика Okta , если вы еще этого не сделали.
Вы также должны клонировать репозиторий GitHub этого блога .
Оболочка
1
git clone https://github.com/oktadeveloper/okta-netty-webflux-example.git
Проект содержит три подкаталога, соответствующие трем разделам этого урока:
netty-hello-world
: очень простой пример того, как создать сервер Nettywebflux-hello-world
: как создать такой же сервер в Spring WebFluxwebflux-oauth2login
: пример того, как добавить логин OAuth2 в приложение Spring WebFlux
Используйте Netty для создания HTTP-сервера
HTTP-серверы являются реализациями протокола HTTP на уровне приложений (OSI Layer 7), поэтому они находятся относительно высоко в интернет-стеке. Если вы разрабатываете REST API, вы разрабатываете поверх API, который предоставляет эту реализацию для вас . В отличие от Netty не обязательно структурировать связь, обеспечить управление сессиями, или даже предложить безопасность, как TLS. Это замечательно, если вы создаете супер низкоуровневое сетевое приложение; однако, возможно, не лучший выбор, если вы создаете REST-сервис.
К счастью, Netty API также предоставляет некоторые вспомогательные классы и функции, которые позволят нам легко интегрировать протокол более высокого уровня, такой как HTTP. В этой части руководства вы будете использовать их для создания простого HTTP-сервера.
Откройте netty-hello-world
проект в вашей любимой IDE или текстовом редакторе.
Сначала взгляните на src/main/java/com/okta/netty/AppServer.java
файл. Этот класс является точкой входа для приложения и устанавливает сервер Netty.
Джава
xxxxxxxxxx
1
package com.okta.netty;
2
...
4
public class AppServer {
6
7
private static final int HTTP_PORT = 8080;
8
9
public void run() throws Exception {
10
11
// Create the multithreaded event loops for the server
12
EventLoopGroup bossGroup = new NioEventLoopGroup();
13
EventLoopGroup workerGroup = new NioEventLoopGroup();
14
15
try {
16
// A helper class that simplifies server configuration
17
ServerBootstrap httpBootstrap = new ServerBootstrap();
18
19
// Configure the server
20
httpBootstrap.group(bossGroup, workerGroup)
21
.channel(NioServerSocketChannel.class)
22
.childHandler(new ServerInitializer()) // <-- Our handler created here
23
.option(ChannelOption.SO_BACKLOG, 128)
24
.childOption(ChannelOption.SO_KEEPALIVE, true);
25
26
// Bind and start to accept incoming connections.
27
ChannelFuture httpChannel = httpBootstrap.bind(HTTP_PORT).sync();
28
29
// Wait until server socket is closed
30
httpChannel.channel().closeFuture().sync();
31
}
32
finally {
33
workerGroup.shutdownGracefully();
34
bossGroup.shutdownGracefully();
35
}
36
}
37
38
public static void main(String[] args) throws Exception {
39
new AppServer().run();
40
}
41
42
}
Наиболее важная строка .childHandler(new ServerInitializer())
, которая создает ServerInitializer
и ServerHandler
подключается к серверу Netty.
Далее посмотрим на src/main/java/com/okta/netty/ServerInitializer.java
. Этот класс настраивает канал Netty, который будет обрабатывать наши запросы и подключать его к ServerHandler
.
Джава
xxxxxxxxxx
1
package com.okta.netty;
2
3
...
4
public class ServerInitializer extends ChannelInitializer<Channel> {
6
7
8
protected void initChannel(Channel ch) {
9
ChannelPipeline pipeline = ch.pipeline();
10
pipeline.addLast(new HttpServerCodec());
11
pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
12
pipeline.addLast(new ServerHandler());
13
}
14
15
}
Наконец, есть src/main/java/com/okta/netty/ServerHandler.java
. Это где фактический запрос отображается, и ответ генерируется.
Джава
xxxxxxxxxx
1
package com.okta.netty;
2
3
...
4
5
public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
6
7
8
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
9
ByteBuf content = Unpooled.copiedBuffer("Hello World!", CharsetUtil.UTF_8);
10
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
11
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
12
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
13
ctx.write(response);
14
ctx.flush();
15
}
16
17
}
Обратите внимание, что в этом классе вы должны преобразовать строку ответа в байтовый буфер. Вы фактически генерируете ответ HTTP и устанавливаете некоторые заголовки напрямую. Это прикладной уровень Интернета (OSI Layer 7). Когда вы вызываете ctx.write(response)
, он отправляет ответ в виде потока байтов по TCP. Команда Netty проделала большую работу, скрывая от нас массу сложности, оставаясь при этом на низкоуровневом транспортном протоколе.
Проверьте свое приложение Netty
Чтобы проверить это приложение Netty, из корневого каталога проекта netty-hello-world
выполните:
Оболочка
xxxxxxxxxx
1
./gradlew run
После завершения загрузки приложения из отдельной оболочки используйте HTTPie для выполнения запроса GET:
Оболочка
xxxxxxxxxx
1
$ http :8080
2
HTTP/1.1 200 OK
4
content-length: 12
5
content-type: text/html
6
Hello World!
Это простой HTTP-сервер, встроенный в Netty. Далее вы будете подниматься по ступенькам абстракции и использовать Spring Boot и WebFlux для упрощения работы.
Передай привет WebFlux на Netty
Как я упоминал ранее, WebFlux является неблокирующей альтернативой Spring MVC. Он поддерживает реактивное программирование с помощью управляемого событиями, асинхронного и неблокирующего подхода к обработке запросов. Он также предоставляет множество функциональных API. Reactor, реактивная серверная библиотека Java, разработанная в тесном сотрудничестве с Spring, обеспечивает аспект реактивных потоков в WebFlux. Однако вы также можете использовать другие библиотеки реактивных потоков.
Напомним, что по умолчанию стартер Spring Boot WebFlux работает на сервере Netty. В следующем примере вы заметите, насколько сложна Spring Boot от вас.
Проект Spring Boot WebFlux находится в webflux-hello-world
подкаталоге репозитория GitHub. Это довольно просто.
Посмотрите на ReactiveApplication
класс. Это стандартный класс приложений Spring Boot. Он просто использует public static void main()
метод и метод @SpringBootApplication
для запуска всей среды приложения Spring Boot.
src/main/java/com/okta/webflux/app/ReactiveApplication.java
Джава
xxxxxxxxxx
1
package com.okta.webflux.app;
2
3
...
4
5
6
public class ReactiveApplication {
7
8
public static void main(String[] args) {
9
SpringApplication.run(ReactiveApplication.class, args);
10
}
11
12
}
ReactiveRouter
Простой маршрутизатор класса, ссылки HTML конечные точки с помощью методов - обработчиков. Вы можете видеть, что он использует внедрение зависимостей для передачи ReactiveHandler
bean-компонента маршрутизатора, который определяет одну конечную точку для /
маршрута.
src/main/java/com/okta/webflux/app/ReactiveRouter.java
Джава
xxxxxxxxxx
1
package com.okta.webflux.app;
2
3
...
4
5
6
public class ReactiveRouter {
7
8
9
public RouterFunction<ServerResponse> route(ReactiveHandler handler) {
10
11
return RouterFunctions
12
.route(RequestPredicates
13
.GET("/")
14
.and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), handler::hello);
15
}
16
}
Это так ReactiveHandler
же просто. Он определяет одну функцию-обработчик, которая возвращает простой текст. Тип Mono<ServerResponse>
возврата - это специальный тип для возврата потока одного элемента. Посмотрите Spring Docs на Понимание Реактивных типов, чтобы узнать больше о возвращаемых типах. Если вы привыкли к Spring MVC, это, вероятно, будет одним из самых незнакомых аспектов WebFlux.
Джава
xxxxxxxxxx
1
package com.okta.webflux.app;
2
3
...
4
5
6
public class ReactiveHandler {
7
8
public Mono<ServerResponse> hello() {
9
return ServerResponse
10
.ok()
11
.contentType(MediaType.TEXT_PLAIN)
12
.body(BodyInserters.fromObject("Hello world!"));
13
}
14
15
}
Откройте оболочку и перейдите в webflux-hello-world
подкаталог проекта.
Запуск проекта с помощью: ./gradlew bootRun
.
Откройте другую оболочку для проверки конечной точки http :8080
.
Оболочка
xxxxxxxxxx
1
HTTP/1.1 200 OK
2
Content-Length: 12
3
Content-Type: text/plain
4
Hello world!
Видите, насколько проще было использовать Spring Boot, чем Netty?
Создать приложение OpenID Connect (OIDC)
Далее вы защитите приложение, используя OAuth 2.0. Это может показаться сложным, но не волнуйтесь. Весна и Okta сговорились сделать это чертовски просто!
Okta является провайдером аутентификации и авторизации SaaS (программное обеспечение как услуга). Мы предоставляем бесплатные аккаунты для разработчиков, чтобы вы могли разрабатывать приложения OIDC без суеты. Зайдите на сайт developer.okta.com и зарегистрируйтесь.
После того как вы проверили свою электронную почту, войдите в систему и выполните следующие действия (если вы входите в систему впервые, вам может потребоваться нажать желтую кнопку « Администратор» , чтобы перейти на панель инструментов разработчика):
- Перейдите в Приложение > Добавить приложение .
- Выберите тип приложения Web и нажмите Next .
- Дайте приложению имя. Я назвал мой «WebFlux OAuth».
- В разделе « Перенаправление входа в систему» URI изменяют значение на
http://localhost:8080/login/oauth2/code/okta
. Остальные значения по умолчанию будут работать. - Нажмите Готово .
Примите к сведению ID клиента и секрет клиента на дне. Они понадобятся тебе через минуту.
Защитите свое приложение с OAuth 2.0
После того, как вы создали приложение OIDC на Okta, вам нужно сделать несколько обновлений в проекте. Если вы хотите пропустить вперед, готовый проект для этой части руководства можно найти в webflux-oauth2login
подкаталоге, но я собираюсь показать вам, как изменить webflux-hello-world
вход в систему .
Сначала добавьте стартовый загрузчик Okta Spring в файл сборки Gradle. Мы упорно трудились , чтобы сделать это как можно проще, и окт Spring ботинка Starter упрощает конфигурацию OAuth. Посмотрите на проект GitHub для начинающих для получения дополнительной информации.
Добавьте следующую зависимость в блок зависимостей вашего build.gradle
файла:
Groovy
xxxxxxxxxx
1
dependencies {
2
...
3
implementation 'com.okta.spring:okta-spring-boot-starter:1.3.0'
4
}
Затем добавьте следующие свойства в src/main/resources/application.properties
файл. Вам необходимо заменить значения в скобках на свой собственный домен Okta и идентификатор клиента.
Вы можете найти свой URI эмитента, открыв инструментальную панель разработчика Okta и перейдя в API > Серверы авторизации и посмотрев в таблице сервер по умолчанию. Идентификатор клиента и секретные данные получены из приложения OIDC, которое вы создали всего минуту назад.
Файлы свойств
xxxxxxxxxx
1
okta.oauth2.issuer={yourIssuerUri}
2
okta.oauth2.client-id={yourClientId}
3
okta.oauth2.client-secret={yourClientSecret}
Теперь запустите приложение: ./gradlew bootRun
.
Выйдите из своей учетной записи разработчика Okta или используйте окно инкогнито и перейдите к (в браузере): http: // localhost: 8080 .
Вам будет предложено войти, используя свою учетную запись Okta.
После того, как вы вошли в систему, вы будете перенаправлены обратно в приложение. Ууу - удачи!
Узнайте больше о Netty, Spring Boot и OAuth 2.0
В этом руководстве вы создали базовое приложение «Hello world» с использованием Netty. Вы видели, как Netty является сверхмощной средой для создания сетевых протоколов TCP и UDP. Вы видели, как он поддерживает неблокирующий ввод-вывод и как Spring WebFlux строится поверх Netty для обеспечения реактивной, неблокирующей среды HTTP-приложений. Затем вы создали приложение «Hello world» в WebFlux, после чего вы использовали Okta в качестве поставщика OAuth 2.0 / OIDC для добавления входа OAuth 2.0 в приложение.
Вы можете увидеть готовый код для этого руководства на GitHub по адресу oktadeveloper / okta-netty-webflux-example .
В дополнение к WebFlux, некоторые мощные сетевые платформы построены поверх Netty. Apple недавно открыла ServiceTalk , библиотеку клиент-сервер реагирующих микросервисов с поддержкой HTTP, HTTP / 2 и gRPC. Существует также Armeria , асинхронная клиент-серверная библиотека HTTP / 2 RPC / REST с открытым исходным кодом, построенная на основе Java 8, Netty, Thrift и gRPC. Его основная цель - помочь инженерам создавать высокопроизводительные асинхронные микросервисы.
Если вы хотите узнать больше о Spring Boot, Spring WebFlux и OAuth 2.0, ознакомьтесь с этими полезными руководствами:
- Начните с Spring Boot, OAuth 2.0 и Okta
- Создавайте реактивные API с помощью Spring WebFlux
- Что, черт возьми, OAuth?
- Начните с Spring Security 5.0 и OIDC
- Идентификационные данные, утверждения и токены - учебник по OpenID Connect, часть 1 из 3
- Создайте безопасный API с помощью Spring Boot и GraphQL
Если у вас есть какие-либо вопросы по этому посту, пожалуйста, добавьте комментарий ниже. Чтобы получить более интересный контент, следите за @oktadev в Twitter или подпишитесь на наш канал на YouTube !
Краткое руководство по Java на Netty было впервые опубликовано в блоге разработчиков Okta 25 ноября 2019 года.