Detect existing DispatcherServlet strategy beans in parent context as well
Closes gh-25290
This commit is contained in:
parent
32238cc996
commit
2497d4285f
|
@ -19,9 +19,11 @@ package org.springframework.web.servlet.config;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
@ -43,6 +45,7 @@ import org.springframework.web.util.UrlPathHelper;
|
|||
* Convenience methods for use in MVC namespace BeanDefinitionParsers.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @author Brian Clozel
|
||||
* @author Marten Deinum
|
||||
* @since 3.1
|
||||
|
@ -67,15 +70,15 @@ public abstract class MvcNamespaceUtils {
|
|||
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
|
||||
|
||||
|
||||
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
|
||||
registerBeanNameUrlHandlerMapping(parserContext, source);
|
||||
registerHttpRequestHandlerAdapter(parserContext, source);
|
||||
registerSimpleControllerHandlerAdapter(parserContext, source);
|
||||
registerHandlerMappingIntrospector(parserContext, source);
|
||||
registerThemeResolver(parserContext, source);
|
||||
registerLocaleResolver(parserContext, source);
|
||||
registerFlashMapManager(parserContext, source);
|
||||
registerViewNameTranslator(parserContext, source);
|
||||
public static void registerDefaultComponents(ParserContext context, @Nullable Object source) {
|
||||
registerBeanNameUrlHandlerMapping(context, source);
|
||||
registerHttpRequestHandlerAdapter(context, source);
|
||||
registerSimpleControllerHandlerAdapter(context, source);
|
||||
registerHandlerMappingIntrospector(context, source);
|
||||
registerLocaleResolver(context, source);
|
||||
registerThemeResolver(context, source);
|
||||
registerViewNameTranslator(context, source);
|
||||
registerFlashMapManager(context, source);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,21 +87,21 @@ public abstract class MvcNamespaceUtils {
|
|||
* @return a RuntimeBeanReference to this {@link UrlPathHelper} instance
|
||||
*/
|
||||
public static RuntimeBeanReference registerUrlPathHelper(
|
||||
@Nullable RuntimeBeanReference urlPathHelperRef, ParserContext parserContext, @Nullable Object source) {
|
||||
@Nullable RuntimeBeanReference urlPathHelperRef, ParserContext context, @Nullable Object source) {
|
||||
|
||||
if (urlPathHelperRef != null) {
|
||||
if (parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)) {
|
||||
parserContext.getRegistry().removeAlias(URL_PATH_HELPER_BEAN_NAME);
|
||||
if (context.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)) {
|
||||
context.getRegistry().removeAlias(URL_PATH_HELPER_BEAN_NAME);
|
||||
}
|
||||
parserContext.getRegistry().registerAlias(urlPathHelperRef.getBeanName(), URL_PATH_HELPER_BEAN_NAME);
|
||||
context.getRegistry().registerAlias(urlPathHelperRef.getBeanName(), URL_PATH_HELPER_BEAN_NAME);
|
||||
}
|
||||
else if (!parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME) &&
|
||||
!parserContext.getRegistry().containsBeanDefinition(URL_PATH_HELPER_BEAN_NAME)) {
|
||||
else if (!context.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME) &&
|
||||
!context.getRegistry().containsBeanDefinition(URL_PATH_HELPER_BEAN_NAME)) {
|
||||
RootBeanDefinition urlPathHelperDef = new RootBeanDefinition(UrlPathHelper.class);
|
||||
urlPathHelperDef.setSource(source);
|
||||
urlPathHelperDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(URL_PATH_HELPER_BEAN_NAME, urlPathHelperDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(urlPathHelperDef, URL_PATH_HELPER_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(URL_PATH_HELPER_BEAN_NAME, urlPathHelperDef);
|
||||
context.registerComponent(new BeanComponentDefinition(urlPathHelperDef, URL_PATH_HELPER_BEAN_NAME));
|
||||
}
|
||||
return new RuntimeBeanReference(URL_PATH_HELPER_BEAN_NAME);
|
||||
}
|
||||
|
@ -109,21 +112,21 @@ public abstract class MvcNamespaceUtils {
|
|||
* @return a RuntimeBeanReference to this {@link PathMatcher} instance
|
||||
*/
|
||||
public static RuntimeBeanReference registerPathMatcher(@Nullable RuntimeBeanReference pathMatcherRef,
|
||||
ParserContext parserContext, @Nullable Object source) {
|
||||
ParserContext context, @Nullable Object source) {
|
||||
|
||||
if (pathMatcherRef != null) {
|
||||
if (parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)) {
|
||||
parserContext.getRegistry().removeAlias(PATH_MATCHER_BEAN_NAME);
|
||||
if (context.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)) {
|
||||
context.getRegistry().removeAlias(PATH_MATCHER_BEAN_NAME);
|
||||
}
|
||||
parserContext.getRegistry().registerAlias(pathMatcherRef.getBeanName(), PATH_MATCHER_BEAN_NAME);
|
||||
context.getRegistry().registerAlias(pathMatcherRef.getBeanName(), PATH_MATCHER_BEAN_NAME);
|
||||
}
|
||||
else if (!parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME) &&
|
||||
!parserContext.getRegistry().containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
|
||||
else if (!context.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME) &&
|
||||
!context.getRegistry().containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
|
||||
RootBeanDefinition pathMatcherDef = new RootBeanDefinition(AntPathMatcher.class);
|
||||
pathMatcherDef.setSource(source);
|
||||
pathMatcherDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(PATH_MATCHER_BEAN_NAME, pathMatcherDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(pathMatcherDef, PATH_MATCHER_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(PATH_MATCHER_BEAN_NAME, pathMatcherDef);
|
||||
context.registerComponent(new BeanComponentDefinition(pathMatcherDef, PATH_MATCHER_BEAN_NAME));
|
||||
}
|
||||
return new RuntimeBeanReference(PATH_MATCHER_BEAN_NAME);
|
||||
}
|
||||
|
@ -204,28 +207,14 @@ public abstract class MvcNamespaceUtils {
|
|||
* Registers an {@link HandlerMappingIntrospector} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerHandlerMappingIntrospector(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
private static void registerHandlerMappingIntrospector(ParserContext context, @Nullable Object source) {
|
||||
if (!context.getRegistry().containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(HandlerMappingIntrospector.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
beanDef.setLazyInit(true);
|
||||
parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, beanDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an {@link FixedThemeResolver} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerThemeResolver(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(FixedThemeResolver.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, beanDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.THEME_RESOLVER_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, beanDef);
|
||||
context.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,27 +222,27 @@ public abstract class MvcNamespaceUtils {
|
|||
* Registers an {@link AcceptHeaderLocaleResolver} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerLocaleResolver(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)) {
|
||||
private static void registerLocaleResolver(ParserContext context, @Nullable Object source) {
|
||||
if (!containsBeanInHierarchy(context, DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(AcceptHeaderLocaleResolver.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, beanDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, beanDef);
|
||||
context.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an {@link SessionFlashMapManager} under a well-known name
|
||||
* Registers an {@link FixedThemeResolver} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerFlashMapManager(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(SessionFlashMapManager.class);
|
||||
private static void registerThemeResolver(ParserContext context, @Nullable Object source) {
|
||||
if (!containsBeanInHierarchy(context, DispatcherServlet.THEME_RESOLVER_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(FixedThemeResolver.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME, beanDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, beanDef);
|
||||
context.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.THEME_RESOLVER_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,13 +250,29 @@ public abstract class MvcNamespaceUtils {
|
|||
* Registers an {@link DefaultRequestToViewNameTranslator} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerViewNameTranslator(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME)) {
|
||||
private static void registerViewNameTranslator(ParserContext context, @Nullable Object source) {
|
||||
if (!containsBeanInHierarchy(context, DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(DefaultRequestToViewNameTranslator.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, beanDef);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME));
|
||||
context.getRegistry().registerBeanDefinition(
|
||||
DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, beanDef);
|
||||
context.registerComponent(
|
||||
new BeanComponentDefinition(beanDef, DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an {@link SessionFlashMapManager} under a well-known name
|
||||
* unless already registered.
|
||||
*/
|
||||
private static void registerFlashMapManager(ParserContext context, @Nullable Object source) {
|
||||
if (!containsBeanInHierarchy(context, DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)) {
|
||||
RootBeanDefinition beanDef = new RootBeanDefinition(SessionFlashMapManager.class);
|
||||
beanDef.setSource(source);
|
||||
beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
context.getRegistry().registerBeanDefinition(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME, beanDef);
|
||||
context.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,4 +295,16 @@ public abstract class MvcNamespaceUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an existing bean of the given name, ideally in the entire
|
||||
* context hierarchy (through a {@code containsBean} call) since this
|
||||
* is also what {@code DispatcherServlet} does, or otherwise just in
|
||||
* the local context (through {@code containsBeanDefinition}).
|
||||
*/
|
||||
private static boolean containsBeanInHierarchy(ParserContext context, String beanName) {
|
||||
BeanDefinitionRegistry registry = context.getRegistry();
|
||||
return (registry instanceof BeanFactory ? ((BeanFactory) registry).containsBean(beanName) :
|
||||
registry.containsBeanDefinition(beanName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.springframework.cache.Cache;
|
|||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
@ -100,6 +101,7 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
|||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor;
|
||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.ParameterizableViewController;
|
||||
|
@ -122,9 +124,12 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider;
|
|||
import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
import org.springframework.web.servlet.resource.WebJarsResourceResolver;
|
||||
import org.springframework.web.servlet.support.SessionFlashMapManager;
|
||||
import org.springframework.web.servlet.theme.CookieThemeResolver;
|
||||
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
|
||||
import org.springframework.web.servlet.view.BeanNameViewResolver;
|
||||
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
||||
import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;
|
||||
import org.springframework.web.servlet.view.InternalResourceView;
|
||||
import org.springframework.web.servlet.view.InternalResourceViewResolver;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
@ -225,10 +230,10 @@ public class MvcNamespaceTests {
|
|||
assertThat(appContext.getBean(ConversionService.class)).isNotNull();
|
||||
assertThat(appContext.getBean(LocalValidatorFactoryBean.class)).isNotNull();
|
||||
assertThat(appContext.getBean(Validator.class)).isNotNull();
|
||||
assertThat(appContext.getBean("themeResolver", ThemeResolver.class)).isNotNull();
|
||||
assertThat(appContext.getBean("localeResolver", LocaleResolver.class)).isNotNull();
|
||||
assertThat(appContext.getBean("flashMapManager", FlashMapManager.class)).isNotNull();
|
||||
assertThat(appContext.getBean("themeResolver", ThemeResolver.class)).isNotNull();
|
||||
assertThat(appContext.getBean("viewNameTranslator", RequestToViewNameTranslator.class)).isNotNull();
|
||||
assertThat(appContext.getBean("flashMapManager", FlashMapManager.class)).isNotNull();
|
||||
|
||||
// default web binding initializer behavior test
|
||||
request = new MockHttpServletRequest("GET", "/");
|
||||
|
@ -262,6 +267,23 @@ public class MvcNamespaceTests {
|
|||
assertThat(introspector.getHandlerMappings().get(1).getClass()).isEqualTo(BeanNameUrlHandlerMapping.class);
|
||||
}
|
||||
|
||||
@Test // gh-25290
|
||||
public void testDefaultConfigWithBeansInParentContext() throws Exception {
|
||||
StaticApplicationContext parent = new StaticApplicationContext();
|
||||
parent.registerSingleton("localeResolver", CookieLocaleResolver.class);
|
||||
parent.registerSingleton("themeResolver", CookieThemeResolver.class);
|
||||
parent.registerSingleton("viewNameTranslator", DefaultRequestToViewNameTranslator.class);
|
||||
parent.registerSingleton("flashMapManager", SessionFlashMapManager.class);
|
||||
parent.refresh();
|
||||
appContext.setParent(parent);
|
||||
|
||||
loadBeanDefinitions("mvc-config.xml");
|
||||
assertThat(appContext.getBean("localeResolver")).isSameAs(parent.getBean("localeResolver"));
|
||||
assertThat(appContext.getBean("themeResolver")).isSameAs(parent.getBean("themeResolver"));
|
||||
assertThat(appContext.getBean("viewNameTranslator")).isSameAs(parent.getBean("viewNameTranslator"));
|
||||
assertThat(appContext.getBean("flashMapManager")).isSameAs(parent.getBean("flashMapManager"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomConversionService() throws Exception {
|
||||
loadBeanDefinitions("mvc-config-custom-conversion-service.xml");
|
||||
|
|
Loading…
Reference in New Issue