diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java
new file mode 100644
index 00000000000..8cb52673373
--- /dev/null
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * 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.reactive.handler;
+
+import org.springframework.context.support.ApplicationObjectSupport;
+import org.springframework.core.Ordered;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.Assert;
+import org.springframework.util.PathMatcher;
+import org.springframework.web.reactive.HandlerMapping;
+import org.springframework.web.util.HttpRequestPathHelper;
+
+/**
+ * Abstract base class for {@link org.springframework.web.reactive.HandlerMapping}
+ * implementations.
+ *
+ * @author Rossen Stoyanchev
+ */
+public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
+ implements HandlerMapping, Ordered {
+
+ private int order = Integer.MAX_VALUE; // default: same as non-Ordered
+
+ private HttpRequestPathHelper pathHelper = new HttpRequestPathHelper();
+
+ private PathMatcher pathMatcher = new AntPathMatcher();
+
+
+ // TODO: CORS
+
+ /**
+ * Specify the order value for this HandlerMapping bean.
+ *
Default value is {@code Integer.MAX_VALUE}, meaning that it's non-ordered.
+ * @see org.springframework.core.Ordered#getOrder()
+ */
+ public final void setOrder(int order) {
+ this.order = order;
+ }
+
+ @Override
+ public final int getOrder() {
+ return this.order;
+ }
+
+ /**
+ * Set if the path should be URL-decoded. This sets the same property on the
+ * underlying path helper.
+ * @see HttpRequestPathHelper#setUrlDecode(boolean)
+ */
+ public void setUrlDecode(boolean urlDecode) {
+ this.pathHelper.setUrlDecode(urlDecode);
+ }
+
+ /**
+ * Set the {@link HttpRequestPathHelper} to use for resolution of lookup
+ * paths. Use this to override the default implementation with a custom
+ * subclass or to share common path helper settings across multiple
+ * HandlerMappings.
+ */
+ public void setPathHelper(HttpRequestPathHelper pathHelper) {
+ this.pathHelper = pathHelper;
+ }
+
+ /**
+ * Return the {@link HttpRequestPathHelper} implementation to use for
+ * resolution of lookup paths.
+ */
+ public HttpRequestPathHelper getPathHelper() {
+ return this.pathHelper;
+ }
+
+ /**
+ * Set the PathMatcher implementation to use for matching URL paths
+ * against registered URL patterns. Default is AntPathMatcher.
+ * @see org.springframework.util.AntPathMatcher
+ */
+ public void setPathMatcher(PathMatcher pathMatcher) {
+ Assert.notNull(pathMatcher, "PathMatcher must not be null");
+ this.pathMatcher = pathMatcher;
+ // this.corsConfigSource.setPathMatcher(pathMatcher);
+ }
+
+ /**
+ * Return the PathMatcher implementation to use for matching URL paths
+ * against registered URL patterns.
+ */
+ public PathMatcher getPathMatcher() {
+ return this.pathMatcher;
+ }
+
+}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
new file mode 100644
index 00000000000..6b23f30ee93
--- /dev/null
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * 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.reactive.result.method;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import reactor.core.publisher.Mono;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.MethodIntrospector;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.reactive.HandlerMapping;
+import org.springframework.web.reactive.handler.AbstractHandlerMapping;
+import org.springframework.web.server.ServerWebExchange;
+
+/**
+ * Abstract base class for {@link HandlerMapping} implementations that define
+ * a mapping between a request and a {@link HandlerMethod}.
+ *
+ *
For each registered handler method, a unique mapping is maintained with
+ * subclasses defining the details of the mapping type {@code }.
+ *
+ * @author Rossen Stoyanchev
+ * @param The mapping for a {@link HandlerMethod} containing the conditions
+ * needed to match the handler method to incoming request.
+ */
+public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping implements InitializingBean {
+
+ /**
+ * Bean name prefix for target beans behind scoped proxies. Used to exclude those
+ * targets from handler method detection, in favor of the corresponding proxies.
+ *
We're not checking the autowire-candidate status here, which is how the
+ * proxy target filtering problem is being handled at the autowiring level,
+ * since autowire-candidate may have been turned to {@code false} for other
+ * reasons, while still expecting the bean to be eligible for handler methods.
+ *
Originally defined in {@link org.springframework.aop.scope.ScopedProxyUtils}
+ * but duplicated here to avoid a hard dependency on the spring-aop module.
+ */
+ private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";
+
+
+ private final MappingRegistry mappingRegistry = new MappingRegistry();
+
+
+ // TODO: handlerMethodMappingNamingStrategy
+
+ /**
+ * Return a (read-only) map with all mappings and HandlerMethod's.
+ */
+ public Map getHandlerMethods() {
+ this.mappingRegistry.acquireReadLock();
+ try {
+ return Collections.unmodifiableMap(this.mappingRegistry.getMappings());
+ }
+ finally {
+ this.mappingRegistry.releaseReadLock();
+ }
+ }
+
+ /**
+ * Return the internal mapping registry. Provided for testing purposes.
+ */
+ MappingRegistry getMappingRegistry() {
+ return this.mappingRegistry;
+ }
+
+ /**
+ * Register the given mapping.
+ *
This method may be invoked at runtime after initialization has completed.
+ * @param mapping the mapping for the handler method
+ * @param handler the handler
+ * @param method the method
+ */
+ public void registerMapping(T mapping, Object handler, Method method) {
+ this.mappingRegistry.register(mapping, handler, method);
+ }
+
+ /**
+ * Un-register the given mapping.
+ *
This method may be invoked at runtime after initialization has completed.
+ * @param mapping the mapping to unregister
+ */
+ public void unregisterMapping(T mapping) {
+ this.mappingRegistry.unregister(mapping);
+ }
+
+
+ // Handler method detection
+
+ /**
+ * Detects handler methods at initialization.
+ */
+ @Override
+ public void afterPropertiesSet() {
+ initHandlerMethods();
+ }
+
+ /**
+ * Scan beans in the ApplicationContext, detect and register handler methods.
+ * @see #isHandler(Class)
+ * @see #getMappingForMethod(Method, Class)
+ * @see #handlerMethodsInitialized(Map)
+ */
+ protected void initHandlerMethods() {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Looking for request mappings in application context: " + getApplicationContext());
+ }
+ String[] beanNames = getApplicationContext().getBeanNamesForType(Object.class);
+
+ for (String beanName : beanNames) {
+ if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
+ Class> beanType = null;
+ try {
+ beanType = getApplicationContext().getType(beanName);
+ }
+ catch (Throwable ex) {
+ // An unresolvable bean type, probably from a lazy bean - let's ignore it.
+ if (logger.isDebugEnabled()) {
+ logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
+ }
+ }
+ if (beanType != null && isHandler(beanType)) {
+ detectHandlerMethods(beanName);
+ }
+ }
+ }
+ handlerMethodsInitialized(getHandlerMethods());
+ }
+
+ /**
+ * Look for handler methods in a handler.
+ * @param handler the bean name of a handler or a handler instance
+ */
+ protected void detectHandlerMethods(final Object handler) {
+ Class> handlerType = (handler instanceof String ?
+ getApplicationContext().getType((String) handler) : handler.getClass());
+ final Class> userType = ClassUtils.getUserClass(handlerType);
+
+ Map methods = MethodIntrospector.selectMethods(userType,
+ (MethodIntrospector.MetadataLookup) method -> getMappingForMethod(method, userType));
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
+ }
+ for (Map.Entry entry : methods.entrySet()) {
+ Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
+ T mapping = entry.getValue();
+ registerHandlerMethod(handler, invocableMethod, mapping);
+ }
+ }
+
+ /**
+ * Register a handler method and its unique mapping. Invoked at startup for
+ * each detected handler method.
+ * @param handler the bean name of the handler or the handler instance
+ * @param method the method to register
+ * @param mapping the mapping conditions associated with the handler method
+ * @throws IllegalStateException if another method was already registered
+ * under the same mapping
+ */
+ protected void registerHandlerMethod(Object handler, Method method, T mapping) {
+ this.mappingRegistry.register(mapping, handler, method);
+ }
+
+ /**
+ * Create the HandlerMethod instance.
+ * @param handler either a bean name or an actual handler instance
+ * @param method the target method
+ * @return the created HandlerMethod
+ */
+ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
+ HandlerMethod handlerMethod;
+ if (handler instanceof String) {
+ String beanName = (String) handler;
+ handlerMethod = new HandlerMethod(beanName,
+ getApplicationContext().getAutowireCapableBeanFactory(), method);
+ }
+ else {
+ handlerMethod = new HandlerMethod(handler, method);
+ }
+ return handlerMethod;
+ }
+
+ /**
+ * Invoked after all handler methods have been detected.
+ * @param handlerMethods a read-only map with handler methods and mappings.
+ */
+ protected void handlerMethodsInitialized(Map handlerMethods) {
+ }
+
+
+ // Handler method lookup
+
+ /**
+ * Look up a handler method for the given request.
+ * @param exchange the current exchange
+ */
+ @Override
+ public Mono