WebMvcAutoConfiguration
WebMvcAutoConfiguration은 스프링부트를 사용하여 autoconfiguration을 적용하여 사용될때 스프링이 WebMvc에 관련된 설정인데 이제 사실 사용자가 애플리케이션 빈을 등록을 할때는 프론트단에 관련된 빈은 @Controller만 등록을 한 경우가 대부분인데 (추후에 나중에 interceptor, filter를 추가하는 경우말고)
암튼 바로 컴파일 후에 실행만 하면 디스패처 서블릿으로 바로 요청과 응답이 된다.
원래 로직인 RequestMapping , HandlerAdapter등등.. 빈으로 다 등록이 자동으로 되어있는데 이것은
일단 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration에 자동설정에 따라 등록이 기본적으로 된다.
그다음에는 스프링부트에서 exceptionHandler나 converter,formatter 등등을 확장을 하는 경우가 있을텐데 이것은
WebMvcConfigurer 을 구현하여서 확장이나 재설정을 할 수 있다.
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
default void addInterceptors(InterceptorRegistry registry) {
}
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
default void addCorsMappings(CorsRegistry registry) {
}
default void addViewControllers(ViewControllerRegistry registry) {
}
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
입맛에 맡게(?) 사용자 설정을 하면된다.
근데 여기서 추가로 RequestMapping , HandlerAdapter는 어디서 재정의나 뭐 어떻게 할 수 있을까..?
WebMvcRegistrations 을 이용하여 할 수 있다.
public interface WebMvcRegistrations {
default RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return null;
}
default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return null;
}
default ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {
return null;
}
}
or
@Configuration
public class SimpleRequestMappingHandlerMapping {
@Bean
public WebMvcRegistrations webMvcRegistrations() {
return new WebMvcRegistrations() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new SimpleRequestMappingHandlerMapping("simple");
}
};
}
}
그러면 개발자가 완벽히 제어를 하는 방법은 뭘까
@EnableWebMvc 를 사용하는 경우이다.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
@Configuration(
proxyBeanMethods = false
)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
public DelegatingWebMvcConfiguration() {
}
@Autowired(
required = false
)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
protected void configurePathMatch(PathMatchConfigurer configurer) {
this.configurers.configurePathMatch(configurer);
}
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
this.configurers.configureContentNegotiation(configurer);
}
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
this.configurers.configureAsyncSupport(configurer);
}
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
this.configurers.configureDefaultServletHandling(configurer);
}
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
this.configurers.addArgumentResolvers(argumentResolvers);
}
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
this.configurers.addReturnValueHandlers(returnValueHandlers);
}
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.configureMessageConverters(converters);
}
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
this.configurers.extendMessageConverters(converters);
}
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);
}
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
}
@Nullable
protected Validator getValidator() {
return this.configurers.getValidator();
}
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return this.configurers.getMessageCodesResolver();
}
WebMvcConfigurationSupport를 상속을 받고 있다.
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
private static final boolean shouldIgnoreXml = SpringProperties.getFlag("spring.xml.ignore");
private static final boolean romePresent;
private static final boolean jaxb2Present;
private static final boolean jackson2Present;
private static final boolean jackson2XmlPresent;
private static final boolean jackson2SmilePresent;
private static final boolean jackson2CborPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
private static final boolean kotlinSerializationJsonPresent;
@Nullable
private ApplicationContext applicationContext;
@Nullable
private ServletContext servletContext;
@Nullable
private List<Object> interceptors;
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
@Nullable
private List<HandlerMethodArgumentResolver> argumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> returnValueHandlers;
@Nullable
private List<HttpMessageConverter<?>> messageConverters;
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
@Nullable
private AsyncSupportConfigurer asyncSupportConfigurer;
public WebMvcConfigurationSupport() {
}
public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Nullable
public final ApplicationContext getApplicationContext() {
return this.applicationContext;
}
public void setServletContext(@Nullable ServletContext servletContext) {
this.servletContext = servletContext;
}
@Nullable
public final ServletContext getServletContext() {
return this.servletContext;
}
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
RequestMappingHandlerMapping mapping = this.createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
mapping.setContentNegotiationManager(contentNegotiationManager);
mapping.setCorsConfigurations(this.getCorsConfigurations());
PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
Boolean useTrailingSlashMatch;
if (pathConfig.getPatternParser() != null) {
mapping.setPatternParser(pathConfig.getPatternParser());
} else {
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
useTrailingSlashMatch = pathConfig.isUseSuffixPatternMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseSuffixPatternMatch(useTrailingSlashMatch);
}
Boolean useRegisteredSuffixPatternMatch = pathConfig.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
}
useTrailingSlashMatch = pathConfig.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
if (pathConfig.getPathPrefixes() != null) {
mapping.setPathPrefixes(pathConfig.getPathPrefixes());
}
return mapping;
}
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping();
}
protected final Object[] getInterceptors(FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
this.addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
protected void addInterceptors(InterceptorRegistry registry) {
}
protected PathMatchConfigurer getPathMatchConfigurer() {
if (this.pathMatchConfigurer == null) {
this.pathMatchConfigurer = new PathMatchConfigurer();
this.configurePathMatch(this.pathMatchConfigurer);
}
return this.pathMatchConfigurer;
}
protected void configurePathMatch(PathMatchConfigurer configurer) {
}
@Bean
public PathPatternParser mvcPatternParser() {
return this.getPathMatchConfigurer().getPatternParserOrDefault();
}
@Bean
public UrlPathHelper mvcUrlPathHelper() {
return this.getPathMatchConfigurer().getUrlPathHelperOrDefault();
}
@Bean
public PathMatcher mvcPathMatcher() {
return this.getPathMatchConfigurer().getPathMatcherOrDefault();
}
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
if (this.contentNegotiationManager == null) {
ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
configurer.mediaTypes(this.getDefaultMediaTypes());
this.configureContentNegotiation(configurer);
this.contentNegotiationManager = configurer.buildContentNegotiationManager();
}
return this.contentNegotiationManager;
}
protected Map<String, MediaType> getDefaultMediaTypes() {
Map<String, MediaType> map = new HashMap(4);
if (romePresent) {
map.put("atom", MediaType.APPLICATION_ATOM_XML);
map.put("rss", MediaType.APPLICATION_RSS_XML);
}
if (!shouldIgnoreXml && (jaxb2Present || jackson2XmlPresent)) {
map.put("xml", MediaType.APPLICATION_XML);
}
if (jackson2Present || gsonPresent || jsonbPresent) {
map.put("json", MediaType.APPLICATION_JSON);
}
if (jackson2SmilePresent) {
map.put("smile", MediaType.valueOf("application/x-jackson-smile"));
}
if (jackson2CborPresent) {
map.put("cbor", MediaType.APPLICATION_CBOR);
}
return map;
}
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
@Bean
@Nullable
public HandlerMapping viewControllerHandlerMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext);
this.addViewControllers(registry);
AbstractHandlerMapping handlerMapping = registry.buildHandlerMapping();
if (handlerMapping == null) {
return null;
} else {
PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
if (pathConfig.getPatternParser() != null) {
handlerMapping.setPatternParser(pathConfig.getPatternParser());
} else {
handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
}
handlerMapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
handlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return handlerMapping;
}
}
protected void addViewControllers(ViewControllerRegistry registry) {
}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2);
PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
if (pathConfig.getPatternParser() != null) {
mapping.setPatternParser(pathConfig.getPatternParser());
} else {
mapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
mapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
}
mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
mapping.setCorsConfigurations(this.getCorsConfigurations());
return mapping;
}
@Bean
public RouterFunctionMapping routerFunctionMapping(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
RouterFunctionMapping mapping = new RouterFunctionMapping();
mapping.setOrder(3);
mapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
mapping.setCorsConfigurations(this.getCorsConfigurations());
mapping.setMessageConverters(this.getMessageConverters());
PathPatternParser patternParser = this.getPathMatchConfigurer().getPatternParser();
if (patternParser != null) {
mapping.setPatternParser(patternParser);
}
return mapping;
}
@Bean
@Nullable
public HandlerMapping resourceHandlerMapping(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
Assert.state(this.applicationContext != null, "No ApplicationContext set");
Assert.state(this.servletContext != null, "No ServletContext set");
PathMatchConfigurer pathConfig = this.getPathMatchConfigurer();
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, this.servletContext, contentNegotiationManager, pathConfig.getUrlPathHelper());
this.addResourceHandlers(registry);
AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
if (handlerMapping == null) {
return null;
} else {
if (pathConfig.getPatternParser() != null) {
handlerMapping.setPatternParser(pathConfig.getPatternParser());
} else {
handlerMapping.setUrlPathHelper(pathConfig.getUrlPathHelperOrDefault());
handlerMapping.setPathMatcher(pathConfig.getPathMatcherOrDefault());
}
handlerMapping.setInterceptors(this.getInterceptors(conversionService, resourceUrlProvider));
handlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return handlerMapping;
}
}
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
}
@Bean
public ResourceUrlProvider mvcResourceUrlProvider() {
ResourceUrlProvider urlProvider = new ResourceUrlProvider();
urlProvider.setUrlPathHelper(this.getPathMatchConfigurer().getUrlPathHelperOrDefault());
urlProvider.setPathMatcher(this.getPathMatchConfigurer().getPathMatcherOrDefault());
return urlProvider;
}
@Bean
@Nullable
public HandlerMapping defaultServletHandlerMapping() {
Assert.state(this.servletContext != null, "No ServletContext set");
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
this.configureDefaultServletHandling(configurer);
return configurer.buildHandlerMapping();
}
protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = this.createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(contentNegotiationManager);
adapter.setMessageConverters(this.getMessageConverters());
adapter.setWebBindingInitializer(this.getConfigurableWebBindingInitializer(conversionService, validator));
adapter.setCustomArgumentResolvers(this.getArgumentResolvers());
adapter.setCustomReturnValueHandlers(this.getReturnValueHandlers());
if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
AsyncSupportConfigurer configurer = this.getAsyncSupportConfigurer();
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
}
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
return new RequestMappingHandlerAdapter();
}
@Bean
public HandlerFunctionAdapter handlerFunctionAdapter() {
HandlerFunctionAdapter adapter = new HandlerFunctionAdapter();
AsyncSupportConfigurer configurer = this.getAsyncSupportConfigurer();
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
return adapter;
}
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(FormattingConversionService mvcConversionService, Validator mvcValidator) {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(mvcConversionService);
initializer.setValidator(mvcValidator);
MessageCodesResolver messageCodesResolver = this.getMessageCodesResolver();
if (messageCodesResolver != null) {
initializer.setMessageCodesResolver(messageCodesResolver);
}
return initializer;
}
@Nullable
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
@Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
this.addFormatters(conversionService);
return conversionService;
}
protected void addFormatters(FormatterRegistry registry) {
}
@Bean
public Validator mvcValidator() {
Validator validator = this.getValidator();
if (validator == null) {
if (ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader())) {
Class clazz;
try {
String className = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
clazz = ClassUtils.forName(className, WebMvcConfigurationSupport.class.getClassLoader());
} catch (LinkageError | ClassNotFoundException var4) {
throw new BeanInitializationException("Failed to resolve default validator class", var4);
}
validator = (Validator)BeanUtils.instantiateClass(clazz);
} else {
validator = new NoOpValidator();
}
}
return (Validator)validator;
}
@Nullable
protected Validator getValidator() {
return null;
}
protected final List<HandlerMethodArgumentResolver> getArgumentResolvers() {
if (this.argumentResolvers == null) {
this.argumentResolvers = new ArrayList();
this.addArgumentResolvers(this.argumentResolvers);
}
return this.argumentResolvers;
}
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
protected final List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
if (this.returnValueHandlers == null) {
this.returnValueHandlers = new ArrayList();
this.addReturnValueHandlers(this.returnValueHandlers);
}
return this.returnValueHandlers;
}
protected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList();
this.configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
this.addDefaultHttpMessageConverters(this.messageConverters);
}
this.extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
if (!shouldIgnoreXml) {
try {
messageConverters.add(new SourceHttpMessageConverter());
} catch (Throwable var3) {
}
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
Jackson2ObjectMapperBuilder builder;
if (!shouldIgnoreXml) {
if (jackson2XmlPresent) {
builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
} else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
}
if (kotlinSerializationJsonPresent) {
messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
}
if (jackson2Present) {
builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
} else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
} else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
protected AsyncSupportConfigurer getAsyncSupportConfigurer() {
if (this.asyncSupportConfigurer == null) {
this.asyncSupportConfigurer = new AsyncSupportConfigurer();
this.configureAsyncSupport(this.asyncSupportConfigurer);
}
return this.asyncSupportConfigurer;
}
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
@Bean
public CompositeUriComponentsContributor mvcUriComponentsContributor(@Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("requestMappingHandlerAdapter") RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
return new CompositeUriComponentsContributor(requestMappingHandlerAdapter.getArgumentResolvers(), conversionService);
}
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
@Bean
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList();
this.configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
this.addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
this.extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers, ContentNegotiationManager mvcContentNegotiationManager) {
ExceptionHandlerExceptionResolver exceptionHandlerResolver = this.createExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager);
exceptionHandlerResolver.setMessageConverters(this.getMessageConverters());
exceptionHandlerResolver.setCustomArgumentResolvers(this.getArgumentResolvers());
exceptionHandlerResolver.setCustomReturnValueHandlers(this.getReturnValueHandlers());
if (jackson2Present) {
exceptionHandlerResolver.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
if (this.applicationContext != null) {
exceptionHandlerResolver.setApplicationContext(this.applicationContext);
}
exceptionHandlerResolver.afterPropertiesSet();
exceptionResolvers.add(exceptionHandlerResolver);
ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
responseStatusResolver.setMessageSource(this.applicationContext);
exceptionResolvers.add(responseStatusResolver);
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
return new ExceptionHandlerExceptionResolver();
}
@Bean
public ViewResolver mvcViewResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
ViewResolverRegistry registry = new ViewResolverRegistry(contentNegotiationManager, this.applicationContext);
this.configureViewResolvers(registry);
if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) {
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.applicationContext, ViewResolver.class, true, false);
if (names.length == 1) {
registry.getViewResolvers().add(new InternalResourceViewResolver());
}
}
ViewResolverComposite composite = new ViewResolverComposite();
composite.setOrder(registry.getOrder());
composite.setViewResolvers(registry.getViewResolvers());
if (this.applicationContext != null) {
composite.setApplicationContext(this.applicationContext);
}
if (this.servletContext != null) {
composite.setServletContext(this.servletContext);
}
return composite;
}
protected void configureViewResolvers(ViewResolverRegistry registry) {
}
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
this.addCorsMappings(registry);
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
protected void addCorsMappings(CorsRegistry registry) {
}
@Bean
@Lazy
public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
return new HandlerMappingIntrospector();
}
@Bean
public LocaleResolver localeResolver() {
return new AcceptHeaderLocaleResolver();
}
@Bean
public ThemeResolver themeResolver() {
return new FixedThemeResolver();
}
@Bean
public FlashMapManager flashMapManager() {
return new SessionFlashMapManager();
}
@Bean
public RequestToViewNameTranslator viewNameTranslator() {
return new DefaultRequestToViewNameTranslator();
}
static {
ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
}
private static final class NoOpValidator implements Validator {
private NoOpValidator() {
}
public boolean supports(Class<?> clazz) {
return false;
}
public void validate(@Nullable Object target, Errors errors) {
}
}
}
이것은 스프링 부트가 autoConfiguration을 해주는 클래스 중에 WebMvcAutoConfiguration을 보면 @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) 이 있는데
이미 WebMvcConfigurationSupport를 상속받아서 사용을 하게 되면
스프링부트가 이미 빈으로 등록이 되어있기때문에 기본 전략을 사용하지 못한다.
@AutoConfiguration(
after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}
)
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
public class WebMvcAutoConfiguration {
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = "";
public static final PathPatternParser pathPatternParser = new PathPatternParser();
private static final String SERVLET_LOCATION = "/";
public WebMvcAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"}
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
@Bean
@ConditionalOnMissingBean({FormContentFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.formcontent.filter",
name = {"enabled"},
matchIfMissing = true
)
public OrderedFormContentFilter formContentFilter() {
return new OrderedFormContentFilter();
}
static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy {
private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP";
private final ContentNegotiationStrategy delegate;
OptionalPathExtensionContentNegotiationStrategy(ContentNegotiationStrategy delegate) {
this.delegate = delegate;
}
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, 0);
return skip != null && Boolean.parseBoolean(skip.toString()) ? MEDIA_TYPE_ALL_LIST : this.delegate.resolveMediaTypes(webRequest);
}
}
static class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {
private final WebProperties.Resources resourceProperties;
ResourceChainResourceHandlerRegistrationCustomizer(WebProperties.Resources resourceProperties) {
this.resourceProperties = resourceProperties;
}
public void customize(ResourceHandlerRegistration registration) {
WebProperties.Resources.Chain properties = this.resourceProperties.getChain();
this.configureResourceChain(properties, registration.resourceChain(properties.isCache()));
}
private void configureResourceChain(WebProperties.Resources.Chain properties, ResourceChainRegistration chain) {
WebProperties.Resources.Chain.Strategy strategy = properties.getStrategy();
if (properties.isCompressed()) {
chain.addResolver(new EncodedResourceResolver());
}
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
chain.addResolver(this.getVersionResourceResolver(strategy));
}
}
private ResourceResolver getVersionResourceResolver(WebProperties.Resources.Chain.Strategy properties) {
VersionResourceResolver resolver = new VersionResourceResolver();
if (properties.getFixed().isEnabled()) {
String version = properties.getFixed().getVersion();
String[] paths = properties.getFixed().getPaths();
resolver.addFixedVersionStrategy(version, paths);
}
if (properties.getContent().isEnabled()) {
String[] paths = properties.getContent().getPaths();
resolver.addContentVersionStrategy(paths);
}
return resolver;
}
}
interface ResourceHandlerRegistrationCustomizer {
void customize(ResourceHandlerRegistration registration);
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnEnabledResourceChain
static class ResourceChainCustomizerConfiguration {
ResourceChainCustomizerConfiguration() {
}
@Bean
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(WebProperties webProperties) {
return new ResourceChainResourceHandlerRegistrationCustomizer(webProperties.getResources());
}
}
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({WebProperties.class})
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private final WebProperties.Resources resourceProperties;
private final WebMvcProperties mvcProperties;
private final WebProperties webProperties;
private final ListableBeanFactory beanFactory;
private final WebMvcRegistrations mvcRegistrations;
private ResourceLoader resourceLoader;
public EnableWebMvcConfiguration(WebMvcProperties mvcProperties, WebProperties webProperties, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ListableBeanFactory beanFactory) {
this.resourceProperties = webProperties.getResources();
this.mvcProperties = mvcProperties;
this.webProperties = webProperties;
this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();
this.beanFactory = beanFactory;
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, @Qualifier("mvcConversionService") FormattingConversionService conversionService, @Qualifier("mvcValidator") Validator validator) {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, conversionService, validator);
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.mvcRegistrations != null) {
RequestMappingHandlerAdapter adapter = this.mvcRegistrations.getRequestMappingHandlerAdapter();
if (adapter != null) {
return adapter;
}
}
return super.createRequestMappingHandlerAdapter();
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
@Bean
@ConditionalOnMissingBean(
name = {"localeResolver"}
)
public LocaleResolver localeResolver() {
if (this.webProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.webProperties.getLocale());
return localeResolver;
}
}
@Bean
@ConditionalOnMissingBean(
name = {"themeResolver"}
)
public ThemeResolver themeResolver() {
return super.themeResolver();
}
@Bean
@ConditionalOnMissingBean(
name = {"flashMapManager"}
)
public FlashMapManager flashMapManager() {
return super.flashMapManager();
}
private Resource getWelcomePage() {
String[] var1 = this.resourceProperties.getStaticLocations();
int var2 = var1.length;
for(int var3 = 0; var3 < var2; ++var3) {
String location = var1[var3];
Resource indexHtml = this.getIndexHtml(location);
if (indexHtml != null) {
return indexHtml;
}
}
ServletContext servletContext = this.getServletContext();
if (servletContext != null) {
return this.getIndexHtml((Resource)(new ServletContextResource(servletContext, "/")));
} else {
return null;
}
}
private Resource getIndexHtml(String location) {
return this.getIndexHtml(this.resourceLoader.getResource(location));
}
private Resource getIndexHtml(Resource location) {
try {
Resource resource = location.createRelative("index.html");
if (resource.exists() && resource.getURL() != null) {
return resource;
}
} catch (Exception var3) {
}
return null;
}
@Bean
public FormattingConversionService mvcConversionService() {
WebMvcProperties.Format format = this.mvcProperties.getFormat();
WebConversionService conversionService = new WebConversionService((new DateTimeFormatters()).dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
this.addFormatters(conversionService);
return conversionService;
}
@Bean
public Validator mvcValidator() {
return !ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader()) ? super.mvcValidator() : ValidatorAdapter.get(this.getApplicationContext(), this.getValidator());
}
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
if (this.mvcRegistrations != null) {
RequestMappingHandlerMapping mapping = this.mvcRegistrations.getRequestMappingHandlerMapping();
if (mapping != null) {
return mapping;
}
}
return super.createRequestMappingHandlerMapping();
}
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(FormattingConversionService mvcConversionService, Validator mvcValidator) {
try {
return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
} catch (NoSuchBeanDefinitionException var4) {
return super.getConfigurableWebBindingInitializer(mvcConversionService, mvcValidator);
}
}
protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
if (this.mvcRegistrations != null) {
ExceptionHandlerExceptionResolver resolver = this.mvcRegistrations.getExceptionHandlerExceptionResolver();
if (resolver != null) {
return resolver;
}
}
return super.createExceptionHandlerExceptionResolver();
}
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
super.extendHandlerExceptionResolvers(exceptionResolvers);
if (this.mvcProperties.isLogResolvedException()) {
Iterator var2 = exceptionResolvers.iterator();
while(var2.hasNext()) {
HandlerExceptionResolver resolver = (HandlerExceptionResolver)var2.next();
if (resolver instanceof AbstractHandlerExceptionResolver) {
((AbstractHandlerExceptionResolver)resolver).setWarnLogCategory(resolver.getClass().getName());
}
}
}
}
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
ContentNegotiationManager manager = super.mvcContentNegotiationManager();
List<ContentNegotiationStrategy> strategies = manager.getStrategies();
ListIterator<ContentNegotiationStrategy> iterator = strategies.listIterator();
while(iterator.hasNext()) {
ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();
if (strategy instanceof PathExtensionContentNegotiationStrategy) {
iterator.set(new OptionalPathExtensionContentNegotiationStrategy(strategy));
}
}
return manager;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
@Configuration(
proxyBeanMethods = false
)
@Import({EnableWebMvcConfiguration.class})
@EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final WebProperties.Resources resourceProperties;
private final WebMvcProperties mvcProperties;
private final ListableBeanFactory beanFactory;
private final ObjectProvider<HttpMessageConverters> messageConvertersProvider;
private final ObjectProvider<DispatcherServletPath> dispatcherServletPath;
private final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
private ServletContext servletContext;
public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = webProperties.getResources();
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
this.mvcProperties.checkConfiguration();
}
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
this.messageConvertersProvider.ifAvailable((customConverters) -> {
converters.addAll(customConverters.getConverters());
});
}
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
if (this.beanFactory.containsBean("applicationTaskExecutor")) {
Object taskExecutor = this.beanFactory.getBean("applicationTaskExecutor");
if (taskExecutor instanceof AsyncTaskExecutor) {
configurer.setTaskExecutor((AsyncTaskExecutor)taskExecutor);
}
}
Duration timeout = this.mvcProperties.getAsync().getRequestTimeout();
if (timeout != null) {
configurer.setDefaultTimeout(timeout.toMillis());
}
}
public void configurePathMatch(PathMatchConfigurer configurer) {
if (this.mvcProperties.getPathmatch().getMatchingStrategy() == MatchingStrategy.PATH_PATTERN_PARSER) {
configurer.setPatternParser(WebMvcAutoConfiguration.pathPatternParser);
}
configurer.setUseSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseSuffixPattern());
configurer.setUseRegisteredSuffixPatternMatch(this.mvcProperties.getPathmatch().isUseRegisteredSuffixPattern());
this.dispatcherServletPath.ifAvailable((dispatcherPath) -> {
String servletUrlMapping = dispatcherPath.getServletUrlMapping();
if (servletUrlMapping.equals("/") && this.singleDispatcherServlet()) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setAlwaysUseFullPath(true);
configurer.setUrlPathHelper(urlPathHelper);
}
});
}
private boolean singleDispatcherServlet() {
Stream var10000 = this.servletRegistrations.stream().map(ServletRegistrationBean::getServlet);
DispatcherServlet.class.getClass();
return var10000.filter(DispatcherServlet.class::isInstance).count() == 1L;
}
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
WebMvcProperties.Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();
configurer.favorPathExtension(contentnegotiation.isFavorPathExtension());
configurer.favorParameter(contentnegotiation.isFavorParameter());
if (contentnegotiation.getParameterName() != null) {
configurer.parameterName(contentnegotiation.getParameterName());
}
Map<String, MediaType> mediaTypes = this.mvcProperties.getContentnegotiation().getMediaTypes();
mediaTypes.forEach(configurer::mediaType);
}
@Bean
@ConditionalOnMissingBean
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
@Bean
@ConditionalOnBean({View.class})
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(2147483637);
return resolver;
}
@Bean
@ConditionalOnBean({ViewResolver.class})
@ConditionalOnMissingBean(
name = {"viewResolver"},
value = {ContentNegotiatingViewResolver.class}
)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
resolver.setOrder(Integer.MIN_VALUE);
return resolver;
}
public MessageCodesResolver getMessageCodesResolver() {
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
return resolver;
} else {
return null;
}
}
public void addFormatters(FormatterRegistry registry) {
ApplicationConversionService.addBeans(registry, this.beanFactory);
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
this.addResourceHandler(registry, pattern, (registration) -> {
registration.addResourceLocations(locations);
});
}
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, Consumer<ResourceHandlerRegistration> customizer) {
if (!registry.hasMappingForPattern(pattern)) {
ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{pattern});
customizer.accept(registration);
registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
this.customizeResourceHandlerRegistration(registration);
}
}
private Integer getSeconds(Duration cachePeriod) {
return cachePeriod != null ? (int)cachePeriod.getSeconds() : null;
}
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
if (this.resourceHandlerRegistrationCustomizer != null) {
this.resourceHandlerRegistrationCustomizer.customize(registration);
}
}
@Bean
@ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})
@ConditionalOnMissingFilterBean({RequestContextFilter.class})
public static RequestContextFilter requestContextFilter() {
return new OrderedRequestContextFilter();
}
}
}
그런데 위에서 거론했던 @EnableWebMvc를 스프링 MVC 구성을 위한 클래스에 선언하면 WebMvcConfigurationSupport을 불러와 스프링 MVC를 구성한다.
-> @EnableWebMvc이것은 스프링부트의 자동설정과는 별게 이다. 아무튼 근데 자동구성을 해주긴한다.
이 과정에서 WebMvcConfigurationSupport가 컴포넌트로 등록되면서 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 조건을 만족시키지 못하게 되어 WebMvcAutoConfiguration은 비활성화 된다.
이와 유사하게 WebMvcConfigurationSupport를 확장한 클래스에 @Configuration를 선언하면 동일하게 적용된다.
결론
(@EnableWebMvc)WebMvcConfigurationSupport을 상속하거나 타입의 빈이 있으면 스프링부트의 WEBmvc자동구성에서 제외.
@EnableWebMvc과 스프링부트의 WebMvcAutoConfiguration의 등록되는 빈의 종류가 한 두개가 덜 등록됨.
뭐였더라... 나중에 작성을 해보자.
암튼 약간의 차이가 있지만 API를 구성하는데에는 지장이 없다.