Skip to content

Commit eb4fc16

Browse files
committedJul 17, 2017
Add customizers for Reactive Web Servers
Closes gh-9572
1 parent 1a0f219 commit eb4fc16

File tree

6 files changed

+245
-2
lines changed

6 files changed

+245
-2
lines changed
 

Diff for: ‎spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java

+40
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
package org.springframework.boot.web.embedded.jetty;
1818

1919
import java.net.InetSocketAddress;
20+
import java.util.ArrayList;
21+
import java.util.Arrays;
22+
import java.util.Collection;
23+
import java.util.List;
2024

2125
import org.apache.commons.logging.Log;
2226
import org.apache.commons.logging.LogFactory;
@@ -34,6 +38,7 @@
3438
import org.springframework.boot.web.server.WebServer;
3539
import org.springframework.http.server.reactive.HttpHandler;
3640
import org.springframework.http.server.reactive.JettyHttpHandlerAdapter;
41+
import org.springframework.util.Assert;
3742

3843
/**
3944
* {@link ReactiveWebServerFactory} that can be used to create {@link JettyWebServer}s.
@@ -56,6 +61,8 @@ public class JettyReactiveWebServerFactory extends AbstractReactiveWebServerFact
5661
*/
5762
private int selectors = -1;
5863

64+
private List<JettyServerCustomizer> jettyServerCustomizers = new ArrayList<>();
65+
5966
private ThreadPool threadPool;
6067

6168
/**
@@ -90,6 +97,9 @@ protected Server createJettyServer(JettyHttpHandlerAdapter servlet) {
9097
ServletContextHandler contextHandler = new ServletContextHandler(server, "",
9198
false, false);
9299
contextHandler.addServlet(servletHolder, "/");
100+
for (JettyServerCustomizer customizer : getServerCustomizers()) {
101+
customizer.customize(server);
102+
}
93103
JettyReactiveWebServerFactory.logger
94104
.info("Server initialized with port: " + port);
95105
return server;
@@ -134,6 +144,36 @@ public void setAcceptors(int acceptors) {
134144
this.acceptors = acceptors;
135145
}
136146

147+
/**
148+
* Sets {@link JettyServerCustomizer}s that will be applied to the {@link Server}
149+
* before it is started. Calling this method will replace any existing customizers.
150+
* @param customizers the Jetty customizers to apply
151+
*/
152+
public void setServerCustomizers(
153+
Collection<? extends JettyServerCustomizer> customizers) {
154+
Assert.notNull(customizers, "Customizers must not be null");
155+
this.jettyServerCustomizers = new ArrayList<>(customizers);
156+
}
157+
158+
/**
159+
* Returns a mutable collection of Jetty {@link JettyServerCustomizer}s that will be applied
160+
* to the {@link Server} before it is created.
161+
* @return the Jetty customizers
162+
*/
163+
public Collection<JettyServerCustomizer> getServerCustomizers() {
164+
return this.jettyServerCustomizers;
165+
}
166+
167+
/**
168+
* Add {@link JettyServerCustomizer}s that will be applied to the {@link Server}
169+
* before it is started.
170+
* @param customizers the customizers to add
171+
*/
172+
public void addServerCustomizers(JettyServerCustomizer... customizers) {
173+
Assert.notNull(customizers, "Customizers must not be null");
174+
this.jettyServerCustomizers.addAll(Arrays.asList(customizers));
175+
}
176+
137177
/**
138178
* Set the number of selector threads to use.
139179
* @param selectors the number of selector threads to use

Diff for: ‎spring-boot/src/main/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactory.java

+38
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFac
5555

5656
private List<TomcatContextCustomizer> tomcatContextCustomizers = new ArrayList<>();
5757

58+
private List<TomcatConnectorCustomizer> tomcatConnectorCustomizers = new ArrayList<>();
59+
5860
/**
5961
* Create a new {@link TomcatServletWebServerFactory} instance.
6062
*/
@@ -132,6 +134,9 @@ protected void customizeConnector(Connector connector) {
132134
// If ApplicationContext is slow to start we want Tomcat not to bind to the socket
133135
// prematurely...
134136
connector.setProperty("bindOnInit", "false");
137+
for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
138+
customizer.customize(connector);
139+
}
135140
}
136141

137142
private void customizeProtocol(AbstractProtocol<?> protocol) {
@@ -173,6 +178,39 @@ public void addContextCustomizers(
173178
this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers));
174179
}
175180

181+
/**
182+
* Set {@link TomcatConnectorCustomizer}s that should be applied to the Tomcat
183+
* {@link Connector} . Calling this method will replace any existing customizers.
184+
* @param tomcatConnectorCustomizers the customizers to set
185+
*/
186+
public void setTomcatConnectorCustomizers(
187+
Collection<? extends TomcatConnectorCustomizer> tomcatConnectorCustomizers) {
188+
Assert.notNull(tomcatConnectorCustomizers,
189+
"TomcatConnectorCustomizers must not be null");
190+
this.tomcatConnectorCustomizers = new ArrayList<>(tomcatConnectorCustomizers);
191+
}
192+
193+
/**
194+
* Add {@link TomcatConnectorCustomizer}s that should be added to the Tomcat
195+
* {@link Connector}.
196+
* @param tomcatConnectorCustomizers the customizers to add
197+
*/
198+
public void addConnectorCustomizers(
199+
TomcatConnectorCustomizer... tomcatConnectorCustomizers) {
200+
Assert.notNull(tomcatConnectorCustomizers,
201+
"TomcatConnectorCustomizers must not be null");
202+
this.tomcatConnectorCustomizers.addAll(Arrays.asList(tomcatConnectorCustomizers));
203+
}
204+
205+
/**
206+
* Returns a mutable collection of the {@link TomcatConnectorCustomizer}s that will be
207+
* applied to the Tomcat {@link Connector} .
208+
* @return the customizers that will be applied
209+
*/
210+
public Collection<TomcatConnectorCustomizer> getTomcatConnectorCustomizers() {
211+
return this.tomcatConnectorCustomizers;
212+
}
213+
176214
/**
177215
* Factory method called to create the {@link TomcatWebServer}. Subclasses can
178216
* override this method to return a different {@link TomcatWebServer} or apply

Diff for: ‎spring-boot/src/main/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactory.java

+41
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@
1616

1717
package org.springframework.boot.web.embedded.undertow;
1818

19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.Collection;
22+
import java.util.List;
23+
1924
import io.undertow.Undertow;
2025

2126
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
2227
import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
2328
import org.springframework.boot.web.server.WebServer;
2429
import org.springframework.http.server.reactive.HttpHandler;
2530
import org.springframework.http.server.reactive.UndertowHttpHandlerAdapter;
31+
import org.springframework.util.Assert;
2632

2733
/**
2834
* {@link ReactiveWebServerFactory} that can be used to create {@link UndertowWebServer}s.
@@ -40,6 +46,8 @@ public class UndertowReactiveWebServerFactory extends AbstractReactiveWebServerF
4046

4147
private Boolean directBuffers;
4248

49+
private List<UndertowBuilderCustomizer> builderCustomizers = new ArrayList<>();
50+
4351
/**
4452
* Create a new {@link UndertowReactiveWebServerFactory} instance.
4553
*/
@@ -78,6 +86,9 @@ private Undertow.Builder createBuilder(int port) {
7886
builder.setDirectBuffers(this.directBuffers);
7987
}
8088
builder.addHttpListener(port, getListenAddress());
89+
for (UndertowBuilderCustomizer customizer : this.builderCustomizers) {
90+
customizer.customize(builder);
91+
}
8192
return builder;
8293
}
8394

@@ -104,4 +115,34 @@ public void setDirectBuffers(Boolean directBuffers) {
104115
this.directBuffers = directBuffers;
105116
}
106117

118+
/**
119+
* Set {@link UndertowBuilderCustomizer}s that should be applied to the Undertow
120+
* {@link Undertow.Builder}. Calling this method will replace any existing customizers.
121+
* @param customizers the customizers to set
122+
*/
123+
public void setBuilderCustomizers(
124+
Collection<? extends UndertowBuilderCustomizer> customizers) {
125+
Assert.notNull(customizers, "Customizers must not be null");
126+
this.builderCustomizers = new ArrayList<>(customizers);
127+
}
128+
129+
/**
130+
* Returns a mutable collection of the {@link UndertowBuilderCustomizer}s that will be
131+
* applied to the Undertow {@link Undertow.Builder} .
132+
* @return the customizers that will be applied
133+
*/
134+
public Collection<UndertowBuilderCustomizer> getBuilderCustomizers() {
135+
return this.builderCustomizers;
136+
}
137+
138+
/**
139+
* Add {@link UndertowBuilderCustomizer}s that should be used to customize the
140+
* Undertow {@link Undertow.Builder}.
141+
* @param customizers the customizers to add
142+
*/
143+
public void addBuilderCustomizers(UndertowBuilderCustomizer... customizers) {
144+
Assert.notNull(customizers, "Customizers must not be null");
145+
this.builderCustomizers.addAll(Arrays.asList(customizers));
146+
}
147+
107148
}

Diff for: ‎spring-boot/src/test/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactoryTests.java

+46-2
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,64 @@
1616

1717
package org.springframework.boot.web.embedded.jetty;
1818

19-
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory;
19+
import java.util.Arrays;
20+
21+
import org.eclipse.jetty.server.Server;
22+
import org.junit.Test;
23+
import org.mockito.InOrder;
24+
2025
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests;
26+
import org.springframework.http.server.reactive.HttpHandler;
27+
28+
import static org.mockito.ArgumentMatchers.any;
29+
import static org.mockito.Mockito.inOrder;
30+
import static org.mockito.Mockito.mock;
2131

2232
/**
2333
* Tests for {@link JettyReactiveWebServerFactory} and {@link JettyWebServer}.
2434
*
2535
* @author Brian Clozel
36+
* @author Madhura Bhave
2637
*/
2738
public class JettyReactiveWebServerFactoryTests
2839
extends AbstractReactiveWebServerFactoryTests {
2940

3041
@Override
31-
protected AbstractReactiveWebServerFactory getFactory() {
42+
protected JettyReactiveWebServerFactory getFactory() {
3243
return new JettyReactiveWebServerFactory(0);
3344
}
3445

46+
@Test
47+
public void setNullServerCustomizersShouldThrowException() {
48+
JettyReactiveWebServerFactory factory = getFactory();
49+
this.thrown.expect(IllegalArgumentException.class);
50+
this.thrown.expectMessage("Customizers must not be null");
51+
factory.setServerCustomizers(null);
52+
}
53+
54+
@Test
55+
public void addNullServerCustomizersShouldThrowException() {
56+
JettyReactiveWebServerFactory factory = getFactory();
57+
this.thrown.expect(IllegalArgumentException.class);
58+
this.thrown.expectMessage("Customizers must not be null");
59+
factory.addServerCustomizers((JettyServerCustomizer[]) null);
60+
}
61+
62+
@Test
63+
public void jettyCustomizersShouldBeInvoked() throws Exception {
64+
HttpHandler handler = mock(HttpHandler.class);
65+
JettyReactiveWebServerFactory factory = getFactory();
66+
JettyServerCustomizer[] configurations = new JettyServerCustomizer[4];
67+
for (int i = 0; i < configurations.length; i++) {
68+
configurations[i] = mock(JettyServerCustomizer.class);
69+
}
70+
factory.setServerCustomizers(Arrays.asList(configurations[0], configurations[1]));
71+
factory.addServerCustomizers(configurations[2], configurations[3]);
72+
this.webServer = factory.getWebServer(handler);
73+
InOrder ordered = inOrder((Object[]) configurations);
74+
for (JettyServerCustomizer configuration : configurations) {
75+
ordered.verify(configuration).customize(any(Server.class));
76+
}
77+
}
78+
3579
}

Diff for: ‎spring-boot/src/test/java/org/springframework/boot/web/embedded/tomcat/TomcatReactiveWebServerFactoryTests.java

+35
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020

2121
import org.apache.catalina.Context;
22+
import org.apache.catalina.connector.Connector;
2223
import org.junit.Test;
2324
import org.mockito.InOrder;
2425

@@ -33,6 +34,7 @@
3334
* Tests for {@link TomcatReactiveWebServerFactory}.
3435
*
3536
* @author Brian Clozel
37+
* @author Madhura Bhave
3638
*/
3739
public class TomcatReactiveWebServerFactoryTests
3840
extends AbstractReactiveWebServerFactoryTests {
@@ -58,4 +60,37 @@ public void tomcatCustomizers() throws Exception {
5860
}
5961
}
6062

63+
@Test
64+
public void setNullConnectorCustomizersShouldThrowException() {
65+
TomcatReactiveWebServerFactory factory = getFactory();
66+
this.thrown.expect(IllegalArgumentException.class);
67+
this.thrown.expectMessage("Customizers must not be null");
68+
factory.setTomcatConnectorCustomizers(null);
69+
}
70+
71+
@Test
72+
public void addNullAddConnectorCustomizersShouldThrowException() {
73+
TomcatReactiveWebServerFactory factory = getFactory();
74+
this.thrown.expect(IllegalArgumentException.class);
75+
this.thrown.expectMessage("Customizers must not be null");
76+
factory.addConnectorCustomizers((TomcatConnectorCustomizer[]) null);
77+
}
78+
79+
@Test
80+
public void tomcatConnectorCustomizersShouldBeInvoked() throws Exception {
81+
TomcatReactiveWebServerFactory factory = getFactory();
82+
HttpHandler handler = mock(HttpHandler.class);
83+
TomcatConnectorCustomizer[] listeners = new TomcatConnectorCustomizer[4];
84+
for (int i = 0; i < listeners.length; i++) {
85+
listeners[i] = mock(TomcatConnectorCustomizer.class);
86+
}
87+
factory.setTomcatConnectorCustomizers(Arrays.asList(listeners[0], listeners[1]));
88+
factory.addConnectorCustomizers(listeners[2], listeners[3]);
89+
this.webServer = factory.getWebServer(handler);
90+
InOrder ordered = inOrder((Object[]) listeners);
91+
for (TomcatConnectorCustomizer listener : listeners) {
92+
ordered.verify(listener).customize(any(Connector.class));
93+
}
94+
}
95+
6196
}

Diff for: ‎spring-boot/src/test/java/org/springframework/boot/web/embedded/undertow/UndertowReactiveWebServerFactoryTests.java

+45
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@
1616

1717
package org.springframework.boot.web.embedded.undertow;
1818

19+
import java.util.Arrays;
20+
21+
import io.undertow.Undertow;
22+
import org.junit.Test;
23+
import org.mockito.InOrder;
24+
1925
import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactoryTests;
26+
import org.springframework.http.server.reactive.HttpHandler;
27+
28+
import static org.mockito.ArgumentMatchers.any;
29+
import static org.mockito.Mockito.inOrder;
30+
import static org.mockito.Mockito.mock;
2031

2132
/**
2233
* Tests for {@link UndertowReactiveWebServerFactory} and {@link UndertowWebServer}.
2334
*
2435
* @author Brian Clozel
36+
* @author Madhura Bhave
2537
*/
2638
public class UndertowReactiveWebServerFactoryTests
2739
extends AbstractReactiveWebServerFactoryTests {
@@ -31,4 +43,37 @@ protected UndertowReactiveWebServerFactory getFactory() {
3143
return new UndertowReactiveWebServerFactory(0);
3244
}
3345

46+
@Test
47+
public void setNullBuilderCustomizersShouldThrowException() {
48+
UndertowReactiveWebServerFactory factory = getFactory();
49+
this.thrown.expect(IllegalArgumentException.class);
50+
this.thrown.expectMessage("Customizers must not be null");
51+
factory.setBuilderCustomizers(null);
52+
}
53+
54+
@Test
55+
public void addNullBuilderCustomizersShouldThrowException() {
56+
UndertowReactiveWebServerFactory factory = getFactory();
57+
this.thrown.expect(IllegalArgumentException.class);
58+
this.thrown.expectMessage("Customizers must not be null");
59+
factory.addBuilderCustomizers((UndertowBuilderCustomizer[]) null);
60+
}
61+
62+
@Test
63+
public void builderCustomizersShouldBeInvoked() throws Exception {
64+
UndertowReactiveWebServerFactory factory = getFactory();
65+
HttpHandler handler = mock(HttpHandler.class);
66+
UndertowBuilderCustomizer[] customizers = new UndertowBuilderCustomizer[4];
67+
for (int i = 0; i < customizers.length; i++) {
68+
customizers[i] = mock(UndertowBuilderCustomizer.class);
69+
}
70+
factory.setBuilderCustomizers(Arrays.asList(customizers[0], customizers[1]));
71+
factory.addBuilderCustomizers(customizers[2], customizers[3]);
72+
this.webServer = factory.getWebServer(handler);
73+
InOrder ordered = inOrder((Object[]) customizers);
74+
for (UndertowBuilderCustomizer customizer : customizers) {
75+
ordered.verify(customizer).customize(any(Undertow.Builder.class));
76+
}
77+
}
78+
3479
}

0 commit comments

Comments
 (0)
Please sign in to comment.