WebHttpHandlerBuilder.java 8.8 KB
Newer Older
1
/*
R
Rossen Stoyanchev 已提交
2
 * Copyright 2002-2017 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.web.server.adapter;

import java.util.ArrayList;
19
import java.util.Arrays;
20 21
import java.util.List;

22
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
23
import org.springframework.beans.factory.annotation.Autowired;
24 25
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
26
import org.springframework.http.codec.ServerCodecConfigurer;
27 28 29 30 31 32 33 34 35
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.handler.ExceptionHandlingWebHandler;
import org.springframework.web.server.handler.FilteringWebHandler;
36
import org.springframework.web.server.session.DefaultWebSessionManager;
37 38 39
import org.springframework.web.server.session.WebSessionManager;

/**
40
 * This builder has two purposes.
41
 *
42 43 44
 * <p>One is to assemble a processing chain that consists of a target
 * {@link WebHandler}, then decorated with a set of {@link WebFilter}'s, then
 * further decorated with a set of {@link WebExceptionHandler}'s.
45
 *
46 47 48 49 50 51 52 53
 * <p>The second purpose is to adapt the resulting processing chain to an
 * {@link HttpHandler} -- the lowest level reactive HTTP handling abstraction,
 * which can then be used with any of the supported runtimes. The adaptation
 * is done with the help of {@link HttpWebHandlerAdapter}.
 *
 * <p>The processing chain can be assembled manually via builder methods, or
 * detected from Spring configuration via
 * {@link #applicationContext(ApplicationContext)}, or a mix of both.
54 55
 *
 * @author Rossen Stoyanchev
56
 * @author Sebastien Deleuze
57
 * @since 5.0
58
 * @see HttpWebHandlerAdapter
59 60 61
 */
public class WebHttpHandlerBuilder {

62 63 64 65 66 67
	/** Well-known name for the target WebHandler in the bean factory. */
	public static final String WEB_HANDLER_BEAN_NAME = "webHandler";

	/** Well-known name for the WebSessionManager in the bean factory. */
	public static final String WEB_SESSION_MANAGER_BEAN_NAME = "webSessionManager";

68 69 70
	/** Well-known name for the ServerCodecConfigurer in the bean factory. */
	public static final String SERVER_CODEC_CONFIGURER_BEAN_NAME = "serverCodecConfigurer";

71

R
Rossen Stoyanchev 已提交
72
	private final WebHandler webHandler;
73 74 75 76 77 78 79

	private final List<WebFilter> filters = new ArrayList<>();

	private final List<WebExceptionHandler> exceptionHandlers = new ArrayList<>();

	private WebSessionManager sessionManager;

80 81
	private ServerCodecConfigurer codecConfigurer;

82 83 84 85

	/**
	 * Private constructor.
	 */
R
Rossen Stoyanchev 已提交
86 87 88
	private WebHttpHandlerBuilder(WebHandler webHandler) {
		Assert.notNull(webHandler, "WebHandler must not be null");
		this.webHandler = webHandler;
89 90 91 92
	}


	/**
R
Rossen Stoyanchev 已提交
93
	 * Static factory method to create a new builder instance.
94
	 * @param webHandler the target handler for the request
95
	 * @return the prepared builder
96
	 */
97 98
	public static WebHttpHandlerBuilder webHandler(WebHandler webHandler) {
		return new WebHttpHandlerBuilder(webHandler);
99 100
	}

101
	/**
R
Rossen Stoyanchev 已提交
102 103
	 * Static factory method to create a new builder instance by detecting beans
	 * in an {@link ApplicationContext}. The following are detected:
104 105 106 107 108 109 110 111 112
	 * <ul>
	 *	<li>{@link WebHandler} [1] -- looked up by the name
	 *	{@link #WEB_HANDLER_BEAN_NAME}.
	 *	<li>{@link WebFilter} [0..N] -- detected by type and ordered,
	 *	see {@link AnnotationAwareOrderComparator}.
	 *	<li>{@link WebExceptionHandler} [0..N] -- detected by type and
	 *	ordered.
	 *	<li>{@link WebSessionManager} [0..1] -- looked up by the name
	 *	{@link #WEB_SESSION_MANAGER_BEAN_NAME}.
113 114
	 *  <li>{@link ServerCodecConfigurer} [0..1] -- looked up by the name
	 *	{@link #SERVER_CODEC_CONFIGURER_BEAN_NAME}.
115 116 117 118 119 120 121 122 123
	 * </ul>
	 * @param context the application context to use for the lookup
	 * @return the prepared builder
	 */
	public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {

		WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
				context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class));

R
Rossen Stoyanchev 已提交
124
		// Autowire lists for @Bean + @Order
125

R
Rossen Stoyanchev 已提交
126 127 128 129
		SortedBeanContainer container = new SortedBeanContainer();
		context.getAutowireCapableBeanFactory().autowireBean(container);
		builder.filters(container.getFilters());
		builder.exceptionHandlers(container.getExceptionHandlers());
130 131 132 133 134 135 136 137 138

		try {
			builder.sessionManager(
					context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class));
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Fall back on default
		}

139 140 141 142 143 144 145 146
		try {
			builder.codecConfigurer(
					context.getBean(SERVER_CODEC_CONFIGURER_BEAN_NAME, ServerCodecConfigurer.class));
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Fall back on default
		}

147 148 149
		return builder;
	}

150

151 152 153
	/**
	 * Add the given filter(s).
	 * @param filters the filter(s) to add
154
that's	 */
155 156 157 158 159 160 161
	public WebHttpHandlerBuilder filter(WebFilter... filters) {
		if (!ObjectUtils.isEmpty(filters)) {
			this.filters.addAll(Arrays.asList(filters));
		}
		return this;
	}

162
	/**
163
	 * Add the given filters.
164 165
	 * @param filters the filters to add
	 */
R
Rossen Stoyanchev 已提交
166
	public WebHttpHandlerBuilder filters(List<? extends WebFilter> filters) {
167
		if (!ObjectUtils.isEmpty(filters)) {
168
			this.filters.addAll(filters);
169 170 171 172 173
		}
		return this;
	}

	/**
174 175 176 177 178 179 180 181 182
	 * Insert the given filter before other configured filters.
	 * @param filter the filters to insert
	 */
	public WebHttpHandlerBuilder prependFilter(WebFilter filter) {
		Assert.notNull(filter, "WebFilter is required");
		this.filters.add(0, filter);
		return this;
	}

183 184 185 186 187 188 189 190 191 192 193
	/**
	 * Add the given exception handler(s).
	 * @param handlers the exception handler(s)
	 */
	public WebHttpHandlerBuilder exceptionHandler(WebExceptionHandler... handlers) {
		if (!ObjectUtils.isEmpty(handlers)) {
			this.exceptionHandlers.addAll(Arrays.asList(handlers));
		}
		return this;
	}

194 195
	/**
	 * Add the given exception handlers.
R
Rossen Stoyanchev 已提交
196
	 * @param handlers the exception handlers
197
	 */
R
Rossen Stoyanchev 已提交
198 199 200
	public WebHttpHandlerBuilder exceptionHandlers(List<WebExceptionHandler> handlers) {
		if (!ObjectUtils.isEmpty(handlers)) {
			this.exceptionHandlers.addAll(handlers);
201 202 203 204
		}
		return this;
	}

205 206 207 208 209 210 211 212 213 214
	/**
	 * Insert the given exception handler before other configured handlers.
	 * @param handler the exception handler to insert
	 */
	public WebHttpHandlerBuilder prependExceptionHandler(WebExceptionHandler handler) {
		Assert.notNull(handler, "WebExceptionHandler is required");
		this.exceptionHandlers.add(0, handler);
		return this;
	}

215 216
	/**
	 * Configure the {@link WebSessionManager} to set on the
217 218
	 * {@link ServerWebExchange WebServerExchange}.
	 * <p>By default {@link DefaultWebSessionManager} is used.
R
Rossen Stoyanchev 已提交
219
	 * @param manager the session manager
220
	 * @see HttpWebHandlerAdapter#setSessionManager(WebSessionManager)
221
	 */
R
Rossen Stoyanchev 已提交
222 223
	public WebHttpHandlerBuilder sessionManager(WebSessionManager manager) {
		this.sessionManager = manager;
224 225 226
		return this;
	}

227 228 229 230 231 232 233 234 235 236
	/**
	 * Configure the {@link ServerCodecConfigurer} to set on the
	 * {@link ServerWebExchange WebServerExchange}.
	 * @param codecConfigurer the codec configurer
	 */
	public WebHttpHandlerBuilder codecConfigurer(ServerCodecConfigurer codecConfigurer) {
		this.codecConfigurer = codecConfigurer;
		return this;
	}

R
Rossen Stoyanchev 已提交
237

238 239 240 241
	/**
	 * Build the {@link HttpHandler}.
	 */
	public HttpHandler build() {
R
Rossen Stoyanchev 已提交
242 243 244 245 246 247 248

		WebHandler decorated;

		decorated = new FilteringWebHandler(this.webHandler, this.filters);
		decorated = new ExceptionHandlingWebHandler(decorated,  this.exceptionHandlers);

		HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
249
		if (this.sessionManager != null) {
R
Rossen Stoyanchev 已提交
250
			adapted.setSessionManager(this.sessionManager);
251
		}
252 253 254
		if (this.codecConfigurer != null) {
			adapted.setCodecConfigurer(this.codecConfigurer);
		}
R
Rossen Stoyanchev 已提交
255 256

		return adapted;
257 258
	}

259

R
Rossen Stoyanchev 已提交
260
	private static class SortedBeanContainer {
261 262 263

		private List<WebFilter> filters;

R
Rossen Stoyanchev 已提交
264 265 266
		private List<WebExceptionHandler> exceptionHandlers;


267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
		@Autowired(required = false)
		public void setFilters(List<WebFilter> filters) {
			this.filters = filters;
		}

		public List<WebFilter> getFilters() {
			return this.filters;
		}

		@Autowired(required = false)
		public void setExceptionHandlers(List<WebExceptionHandler> exceptionHandlers) {
			this.exceptionHandlers = exceptionHandlers;
		}

		public List<WebExceptionHandler> getExceptionHandlers() {
			return this.exceptionHandlers;
		}
	}

286
}