Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 591ab8a

Browse files
committed
@EnableWebFlux setup supports WebSocketHandler
Closes spring-projectsgh-22587
1 parent 8f369ff commit 591ab8a

8 files changed

Lines changed: 183 additions & 18 deletions

File tree

spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.validation.Validator;
2828
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
2929
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
30+
import org.springframework.web.reactive.socket.server.WebSocketService;
3031

3132
/**
3233
* A subclass of {@code WebFluxConfigurationSupport} that detects and delegates
@@ -98,6 +99,12 @@ protected MessageCodesResolver getMessageCodesResolver() {
9899
return (messageCodesResolver != null ? messageCodesResolver : super.getMessageCodesResolver());
99100
}
100101

102+
@Override
103+
protected WebSocketService getWebSocketService() {
104+
WebSocketService service = this.configurers.getWebSocketService();
105+
return (service != null ? service : super.getWebSocketService());
106+
}
107+
101108
@Override
102109
protected void configureViewResolvers(ViewResolverRegistry registry) {
103110
this.configurers.configureViewResolvers(registry);

spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
import org.springframework.web.reactive.result.method.annotation.ResponseEntityResultHandler;
6666
import org.springframework.web.reactive.result.view.ViewResolutionResultHandler;
6767
import org.springframework.web.reactive.result.view.ViewResolver;
68+
import org.springframework.web.reactive.socket.server.WebSocketService;
69+
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
6870
import org.springframework.web.server.ServerWebExchange;
6971
import org.springframework.web.server.WebExceptionHandler;
7072
import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;
@@ -431,6 +433,24 @@ public SimpleHandlerAdapter simpleHandlerAdapter() {
431433
return new SimpleHandlerAdapter();
432434
}
433435

436+
@Bean
437+
public WebSocketHandlerAdapter webFluxWebSocketHandlerAdapter() {
438+
WebSocketService service = getWebSocketService();
439+
WebSocketHandlerAdapter adapter = (service != null ?
440+
new WebSocketHandlerAdapter(service) : new WebSocketHandlerAdapter());
441+
442+
// For backwards compatibility, lower the (default) priority
443+
int defaultOrder = adapter.getOrder();
444+
adapter.setOrder(defaultOrder + 1);
445+
446+
return adapter;
447+
}
448+
449+
@Nullable
450+
protected WebSocketService getWebSocketService() {
451+
return null;
452+
}
453+
434454
@Bean
435455
public ResponseEntityResultHandler responseEntityResultHandler(
436456
@Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,

spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurer.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
import org.springframework.validation.Validator;
2626
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
2727
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
28+
import org.springframework.web.reactive.socket.server.WebSocketService;
2829

2930
/**
3031
* Defines callback methods to customize the configuration for WebFlux
@@ -124,6 +125,18 @@ default MessageCodesResolver getMessageCodesResolver() {
124125
return null;
125126
}
126127

128+
/**
129+
* Provide the {@link WebSocketService} to create
130+
* {@link org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter}
131+
* with. This can be used to configure server-specific properties through the
132+
* {@link org.springframework.web.reactive.socket.server.RequestUpgradeStrategy}.
133+
* @since 5.3
134+
*/
135+
@Nullable
136+
default WebSocketService getWebSocketService() {
137+
return null;
138+
}
139+
127140
/**
128141
* Configure view resolution for rendering responses with a view and a model,
129142
* where the view is typically an HTML template but could also be based on

spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurerComposite.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
3030
import org.springframework.validation.Validator;
3131
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
3232
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
33+
import org.springframework.web.reactive.socket.server.WebSocketService;
3334

3435
/**
3536
* A {@link WebFluxConfigurer} that delegates to one or more others.
@@ -70,6 +71,12 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
7071
this.delegates.forEach(delegate -> delegate.addResourceHandlers(registry));
7172
}
7273

74+
@Nullable
75+
@Override
76+
public WebSocketService getWebSocketService() {
77+
return createSingleBean(WebFluxConfigurer::getWebSocketService, WebSocketService.class);
78+
}
79+
7380
@Override
7481
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
7582
this.delegates.forEach(delegate -> delegate.configureArgumentResolvers(configurer));

spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,27 +17,39 @@
1717

1818
import reactor.core.publisher.Mono;
1919

20+
import org.springframework.core.Ordered;
2021
import org.springframework.util.Assert;
21-
import org.springframework.web.reactive.DispatcherHandler;
2222
import org.springframework.web.reactive.HandlerAdapter;
2323
import org.springframework.web.reactive.HandlerResult;
2424
import org.springframework.web.reactive.socket.WebSocketHandler;
2525
import org.springframework.web.reactive.socket.server.WebSocketService;
2626
import org.springframework.web.server.ServerWebExchange;
2727

2828
/**
29-
* {@link HandlerAdapter} that allows using a {@link WebSocketHandler} with the
30-
* generic {@link DispatcherHandler} mapping URLs directly to such handlers.
31-
* Requests are handled by delegating to the configured {@link WebSocketService}
32-
* which by default is {@link HandshakeWebSocketService}.
29+
* {@code HandlerAdapter} that allows
30+
* {@link org.springframework.web.reactive.DispatcherHandler} to support
31+
* handlers of type {@link WebSocketHandler} with such handlers mapped to
32+
* URL patterns via
33+
* {@link org.springframework.web.reactive.handler.SimpleUrlHandlerMapping}.
34+
*
35+
* <p>Requests are handled by delegating to a
36+
* {@link WebSocketService}, by default {@link HandshakeWebSocketService},
37+
* which checks the WebSocket handshake request parameters, upgrades to a
38+
* WebSocket interaction, and uses the {@link WebSocketHandler} to handle it.
39+
*
40+
* <p>As of 5.3 the WebFlux Java configuration, imported via
41+
* {@code @EnableWebFlux}, includes a declaration of this adapter and therefore
42+
* it no longer needs to be present in application configuration.
3343
*
3444
* @author Rossen Stoyanchev
3545
* @since 5.0
3646
*/
37-
public class WebSocketHandlerAdapter implements HandlerAdapter {
47+
public class WebSocketHandlerAdapter implements HandlerAdapter, Ordered {
3848

3949
private final WebSocketService webSocketService;
4050

51+
private int order = 2;
52+
4153

4254
/**
4355
* Default constructor that creates and uses a
@@ -56,6 +68,25 @@ public WebSocketHandlerAdapter(WebSocketService webSocketService) {
5668
}
5769

5870

71+
/**
72+
* Set the order value for this adapter.
73+
* <p>By default this is set to 2.
74+
* @param order the value to set to
75+
* @since 5.3
76+
*/
77+
public void setOrder(int order) {
78+
this.order = order;
79+
}
80+
81+
/**
82+
* Return the {@link #setOrder(int) configured} order for this instance.
83+
* @since 5.3
84+
*/
85+
@Override
86+
public int getOrder() {
87+
return this.order;
88+
}
89+
5990
/**
6091
* Return the configured {@code WebSocketService} to handle requests.
6192
*/

spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,14 @@
3737
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
3838
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
3939
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
40+
import org.springframework.web.reactive.socket.server.WebSocketService;
41+
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
4042

4143
import static org.assertj.core.api.Assertions.assertThat;
4244
import static org.mockito.ArgumentMatchers.any;
4345
import static org.mockito.BDDMockito.given;
4446
import static org.mockito.BDDMockito.willAnswer;
47+
import static org.mockito.Mockito.mock;
4548
import static org.mockito.Mockito.verify;
4649

4750
/**
@@ -73,6 +76,7 @@ public void setup() {
7376
delegatingConfig.setApplicationContext(new StaticApplicationContext());
7477
given(webFluxConfigurer.getValidator()).willReturn(null);
7578
given(webFluxConfigurer.getMessageCodesResolver()).willReturn(null);
79+
given(webFluxConfigurer.getWebSocketService()).willReturn(null);
7680
}
7781

7882

@@ -125,6 +129,17 @@ public void resourceHandlerMapping() {
125129
verify(webFluxConfigurer).configurePathMatching(any(PathMatchConfigurer.class));
126130
}
127131

132+
@Test
133+
void webSocketService() {
134+
WebSocketService service = mock(WebSocketService.class);
135+
given(webFluxConfigurer.getWebSocketService()).willReturn(service);
136+
137+
delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer));
138+
WebSocketHandlerAdapter adapter = delegatingConfig.webFluxWebSocketHandlerAdapter();
139+
140+
assertThat(adapter.getWebSocketService()).isSameAs(service);
141+
}
142+
128143
@Test
129144
public void responseBodyResultHandler() {
130145
delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer));

src/docs/asciidoc/web/webflux-websocket.adoc

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The following example shows how to do so:
5454
}
5555
----
5656

57-
Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the following example shows:
57+
Then you can map it to a URL:
5858

5959
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
6060
.Java
@@ -70,11 +70,6 @@ Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the followi
7070
7171
return new SimpleUrlHandlerMapping(map, order);
7272
}
73-
74-
@Bean
75-
public WebSocketHandlerAdapter handlerAdapter() {
76-
return new WebSocketHandlerAdapter();
77-
}
7873
}
7974
----
8075
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
@@ -90,6 +85,34 @@ Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the followi
9085
9186
return SimpleUrlHandlerMapping(map, order)
9287
}
88+
}
89+
----
90+
91+
If using the <<web-reactive.adoc#webflux-config, WebFlux Config>> there is nothing
92+
further to do, or otherwise if not using the WebFlux config you'll need to declare a
93+
`WebSocketHandlerAdapter` as shown below:
94+
95+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
96+
.Java
97+
----
98+
@Configuration
99+
class WebConfig {
100+
101+
// ...
102+
103+
@Bean
104+
public WebSocketHandlerAdapter handlerAdapter() {
105+
return new WebSocketHandlerAdapter();
106+
}
107+
}
108+
----
109+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
110+
.Kotlin
111+
----
112+
@Configuration
113+
class WebConfig {
114+
115+
// ...
93116
94117
@Bean
95118
fun handlerAdapter() = WebSocketHandlerAdapter()
@@ -333,9 +356,11 @@ into the attributes of the `WebSocketSession`.
333356
=== Server Configation
334357
[.small]#<<web.adoc#websocket-server-runtime-configuration, Same as in the Servlet stack>>#
335358

336-
The `RequestUpgradeStrategy` for each server exposes WebSocket-related configuration
337-
options available for the underlying WebSocket engine. The following example sets
338-
WebSocket options when running on Tomcat:
359+
The `RequestUpgradeStrategy` for each server exposes configuration specific to the
360+
underlying WebSocket server engine. When using the WebFlux Java config you can customize
361+
such properties as shown in the corresponding section of the
362+
<<web-reactive.adoc#webflux-config-websocket-service, WebFlux Config>>, or otherwise if
363+
not using the WebFlux config, use the below:
339364

340365
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
341366
.Java

src/docs/asciidoc/web/webflux.adoc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4289,6 +4289,53 @@ reliance on it.
42894289

42904290

42914291

4292+
[[webflux-config-websocket-service]]
4293+
=== WebSocketService
4294+
4295+
The WebFlux Java config declares of a `WebSocketHandlerAdapter` bean which provides
4296+
support for the invocation of WebSocket handlers. That means all that remains to do in
4297+
order to handle a WebSocket handshake request is to map a `WebSocketHandler` to a URL
4298+
via `SimpleUrlHandlerMapping`.
4299+
4300+
In some cases it may be necessary to create the `WebSocketHandlerAdapter` bean with a
4301+
provided `WebSocketService` service which allows configuring WebSocket server properties.
4302+
For example:
4303+
4304+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
4305+
.Java
4306+
----
4307+
@Configuration
4308+
@EnableWebFlux
4309+
public class WebConfig implements WebFluxConfigurer {
4310+
4311+
@Override
4312+
public WebSocketService getWebSocketService() {
4313+
TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
4314+
strategy.setMaxSessionIdleTimeout(0L);
4315+
return new HandshakeWebSocketService(strategy);
4316+
}
4317+
}
4318+
----
4319+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
4320+
.Kotlin
4321+
----
4322+
@Configuration
4323+
@EnableWebFlux
4324+
class WebConfig : WebFluxConfigurer {
4325+
4326+
@Override
4327+
fun webSocketService(): WebSocketService {
4328+
val strategy = TomcatRequestUpgradeStrategy().apply {
4329+
setMaxSessionIdleTimeout(0L)
4330+
}
4331+
return HandshakeWebSocketService(strategy)
4332+
}
4333+
}
4334+
----
4335+
4336+
4337+
4338+
42924339
[[webflux-config-advanced-java]]
42934340
=== Advanced Configuration Mode
42944341
[.small]#<<web.adoc#mvc-config-advanced-java, Web MVC>>#

0 commit comments

Comments
 (0)